Skip to content

添加自定义组件物料

引擎内置只提供了基础的 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>
);
};

注意事项

  1. 物料格式:物料对象需要包含 meta 属性,它是一个物料数组
  2. 资源格式:编辑器模式下必须使用 UMD 格式的资源,资源会在 iframe 中动态加载
  3. 全局变量名globalName 需要与组件库导出的全局变量名一致
  4. 包名匹配assetPackagesList 中的 package 需要与物料中的 npm.package 字段匹配
  5. 渲染页面:生产环境可以直接使用 npm 包,无需 UMD 资源