添加自定义组件物料
引擎内置只提供了基础的 HTML Tag 组件以及对应的物料, 如: div、p、video…等等,如果需要扩展使用自定义的物料,参考如下方式
编辑器配置
导入组件物料
首先需要导入自定义组件的物料描述。物料通常以 npm 包的形式提供,包含组件的元数据信息:
import { Engine, InnerComponentMeta, plugins } from '@chamn/engine';import '@chamn/engine/dist/style.css';
// 导入自定义物料(假设物料包为 @custom/material)import customMaterial from '@custom/material/dist/meta';
// 或者从本地文件导入// import customMaterial from './material/meta';
const { DEFAULT_PLUGIN_LIST } = plugins;配置资源包列表
编辑器模式下需要提供组件的 UMD 格式资源(JS 和 CSS),这些资源会在编辑器的 iframe 中加载:
// 方式一:使用 CDN 资源const assetPackagesList = [ { package: '@custom/material', globalName: 'CustomMaterial', resources: [ { src: 'https://cdn.example.com/custom-material.umd.js', }, { src: 'https://cdn.example.com/custom-material.css', }, ], },];
// 方式二:使用本地资源(推荐使用 ?url 后缀导入, vite 构建工具会自动处理,其他工具需要自行处理)import customMaterialJS from '@custom/material/dist/index.umd.js?url';import customMaterialCSS from '@custom/material/dist/style.css?url';
const assetPackagesList = [ { package: '@custom/material', globalName: 'CustomMaterial', resources: [ { src: customMaterialJS, }, { src: customMaterialCSS, }, ], },];完整示例
import { useState, useEffect } from 'react';import { Engine, InnerComponentMeta, plugins, EnginContext } from '@chamn/engine';import '@chamn/engine/dist/style.css';
// 导入自定义物料import customMaterial from '@custom/material/dist/meta';
// 导入资源文件import customMaterialJS from '@custom/material/dist/index.umd.js?url';import customMaterialCSS from '@custom/material/dist/style.css?url';
const { DEFAULT_PLUGIN_LIST } = plugins;
const assetPackagesList = [ { package: customMaterial.package || '@custom/material', globalName: customMaterial.globalName || 'CustomMaterial', resources: [ { src: customMaterialJS, }, { src: customMaterialCSS, }, ], },];
function Editor() { const [page, setPage] = useState(null);
useEffect(() => { // 从本地存储加载页面数据 const localPage = localStorage.getItem('pageSchema'); if (localPage) { setPage(JSON.parse(localPage)); } }, []);
const onReady = (ctx: EnginContext) => { console.log('Engine ready!', ctx); };
return ( <Engine plugins={DEFAULT_PLUGIN_LIST} schema={page} // 传入组件物料,合并内置物料和自定义物料 material={[...InnerComponentMeta, ...customMaterial.meta]} // 传入组件物料对应的 UMD 资源 assetPackagesList={assetPackagesList} onReady={onReady} /> );}动态更新物料
如果需要在运行时动态添加物料,可以使用 engine.updateMaterials API:
const onReady = async (ctx: EnginContext) => { // 动态添加新的物料和资源 await ctx.engine.updateMaterials( [ // 新的物料数组 { componentName: 'NewComponent', title: '新组件', // ... 其他物料配置 }, ], [ // 新的资源包列表 { package: 'new-package', globalName: 'NewPackage', resources: [ { src: 'https://cdn.example.com/new-package.umd.js', }, ], }, ] );};渲染页面配置
渲染页面(预览/生产环境)可以直接 import npm 包,不需要提供 UMD 格式的资源:
import { useEffect, useState } from 'react';import { ReactAdapter, Render, useRender } from '@chamn/render';import { CPageDataType } from '@chamn/model';
// 直接导入组件库import * as antd from 'antd';import CustomComps from '@custom/material';
const components = { ...antd, ...CustomComps,};
export const Preview = () => { const [page, setPage] = useState<CPageDataType>(); const renderHandle = useRender(); const [loading, setLoading] = useState(true);
useEffect(() => { const localPage = localStorage.getItem('pageSchema'); if (localPage) { setPage(JSON.parse(localPage)); setLoading(false); } }, []);
if (loading) { return <>未找到页面信息,请确保已在编辑器中保存</>; }
return ( <div className="App" style={{ overflow: 'auto', height: '100%' }}> <Render page={page} components={components} render={renderHandle} adapter={ReactAdapter} /> </div> );};注意事项
- 物料格式:物料对象需要包含
meta属性,它是一个物料数组 - 资源格式:编辑器模式下必须使用 UMD 格式的资源,资源会在 iframe 中动态加载
- 全局变量名:
globalName需要与组件库导出的全局变量名一致 - 包名匹配:
assetPackagesList中的package需要与物料中的npm.package字段匹配 - 渲染页面:生产环境可以直接使用 npm 包,无需 UMD 资源