初始化项目安装依赖失败
依赖包有版本冲突,根据提示忽略即可
npm install --force
// 或者
npm install --legacy-peer-deps
初始化编辑器
import { init } from '@alilc/lowcode-engine';
async function registerPlugins() {
// 注册插件
}
(async function main() {
await registerPlugins();
// 配置文档: https://lowcode-engine.cn/site/docs/api/configOptions#%E9%85%8D%E7%BD%AE%E8%AF%A6%E6%83%85
init(document.getElementById('lce-container')!, {
// 语言,默认值:'zh-CN'
locale: 'zh-CN',
// 是否开启 condition(条件渲染) 的能力,默认在设计器中不管 condition 是啥都正常展示
enableCondition: true,
// 打开画布的锁定操作,默认值:false
enableCanvasLock: true,
// 开启设计器右键菜单能力
enableContextMenu :true,
// 开启应用级设计模式(多页面)
enableWorkspaceMode: true,
// 应用级设计模式下,自动打开第一个窗口
enableAutoOpenFirstWindow: false,
// 是否禁止默认的设置器
disableDefaultSetters: true,
// 默认绑定变量
supportVariableGlobally: true,
simulatorUrl: [
'externals/css/react-simulator-renderer.css',
'externals/js/react-simulator-renderer.js',
],
requestHandlersMap: {
fetch: createFetchHandler(),
},
appHelper,
//自定义设备
device: 'phone',
});
})();
ArraySetter渲染异常
版本信息
异常信息
TypeError: this.context.create is not a function
问题定位
查看官方issue,发现其他人也有类似问题
也尝试切换使用
@alilc/lowcode-engine、@alilc/lowcode-engine-ext的多个版本,也还是报错
通过debug和查看源码发现,根本原因是ObjectSetter内部的错误,决定重写ObjectSetter
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
import AliLowCodeEngineExt from '@alilc/lowcode-engine-ext';
import ObjectSetter from './object-setter';
import { isPlainObject } from './utils';
const DataObjectSetter = {
component: ObjectSetter,
// todo: defaultProps
defaultProps: {},
title: 'ObjectSetter', // TODO
condition: (field: any) => {
const v = field.getValue();
return v == null || isPlainObject(v);
},
initialValue: {},
recommend: true,
};
// 设置内置 setter 和事件绑定、插件绑定面板
const DefaultSettersRegistryPlugin = (ctx: IPublicModelPluginContext) => {
return {
async init() {
AliLowCodeEngineExt.setters.ObjectSetter = ObjectSetter;
AliLowCodeEngineExt.setterMap.ObjectSetter = DataObjectSetter;
const { setterMap } = AliLowCodeEngineExt;
const { setters } = ctx;
// 注册 setterMap
setters.registerSetter(setterMap);
},
};
};
DefaultSettersRegistryPlugin.pluginName = 'DefaultSettersRegistryPlugin';
export default DefaultSettersRegistryPlugin;
- 重写ObjectSetter
render方法
render() {
const { mode, forceInline = 0, ...props } = this.props;
let children;
if (forceInline || mode === 'popup') {
if (forceInline > 2 || mode === 'popup') {
// popup
children = <RowSetter {...props} primaryButton={!forceInline} />;
} else {
children = <RowSetter columns={forceInline > 1 ? 2 : 4} {...props} />;
}
} else {
children = <FormSetter {...props} />;
}
// 主要是这里套了一层PopupService
return <PopupService>{children}</PopupService>;
}
- 解决popup多次弹窗的问题
export class PopupPipe {
private emitter: IEventBus = createModuleEventBus('PopupPipe');
// 重写popup方法,加入actionKey的条件判断即可
private popup(props: PopupProps, target?: Element) {
if (!props.actionKey) return;
Promise.resolve().then(() => {
this.emitter.emit('popupchange', props, target);
});
}
}
跨页面复制节点重新生成节点ID
在开启了应用级设计模式时,可能存在跨页面复制节点又不需要重新生成节点ID的情况
// ctx 为插件上下文
const { material, canvas, common } = ctx;
const { clipboard } = canvas;
function getNodesSchema(nodes: IPublicModelNode[]) {
const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Render));
const data = { type: 'nodeSchema', componentsMap: {}, componentsTree };
return data;
}
material.addContextMenuOption({
name: '跨页面复制',
title: '跨页面复制'
action(nodes, event) {
if (!nodes || nodes.length < 1) return;
const data = getNodesSchema(nodes);
clipboard.setData(data);
}
});
Page根组件添加属性
默认情况下,页面的根节点组件是没有属性的
翻看源码可以发现,如果物料组件里有Page组件,那么就会使用传递过来的Page,反之用默认的 github.com/alibaba/low…
所以我们只需要在我们的物料工程里编译后的lowcode文件夹里新增一个page的meta.ts文件即可
import { IPublicTypeComponentMetadata, IPublicTypeSnippet } from '@alilc/lowcode-types';
import { genBaseSetting, layoutSetting } from '../../src/utils/baseSetting';
const PageMeta: IPublicTypeComponentMetadata = {
'componentName': 'Page',
'title': 'Page',
'docUrl': '',
'screenshot': '',
'devMode': 'proCode',
'npm': {
'package': 'material-components',
'version': '0.1.0',
'exportName': 'Page',
'main': 'src\\index.tsx',
'destructuring': true,
'subName': '',
},
// 'configure': {
// 'props': [
// {
// 'title': {
// 'label': {
// 'type': 'i18n',
// 'en-US': 'isShowFooter',
// 'zh-CN': '展示页尾',
// },
// 'tip': '展示页尾',
// },
// 'name': 'isShowFooter',
// condition: () => false,
// 'description': '展示页尾',
// 'setter': {
// 'componentName': 'BoolSetter',
// 'isRequired': true,
// 'initialValue': false,
// },
// },
// ],
// 'supports': {
// 'style': true,
// events: ['init'],
// },
// 'component': {
// isContainer: true,
// },
// },
props: [
{
name: 'style',
propType: 'object',
defaultValue: {
padding: 12,
},
},
],
configure: {
props: [
genBaseSetting('Page'),
{
'title': '常规设置',
'display': 'accordion',
'type': 'group',
'items': [],
},
layoutSetting(),
],
supports: {
style: true,
className: true,
events: ['init'],
},
component: {
isContainer: true,
disableBehaviors: '*',
},
},
};
const snippets: IPublicTypeSnippet[] = [
{
'title': 'Page',
'screenshot': '',
'schema': {
'componentName': 'Page',
'props': {},
},
},
];
export default {
...PageMeta,
snippets,
};
注入环境变量
// build.plugin.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = ({ onGetWebpackConfig, onHook }) => {
onGetWebpackConfig((config) => {
config.plugin('define').use(webpack.DefinePlugin, [
{
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
// ....
},
]);
});
};
编译多入口
// build.plugin.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = ({ onGetWebpackConfig, onHook }) => {
onGetWebpackConfig((config) => {
config.plugin('index').use(HtmlWebpackPlugin, [
{
inject: false,
minify: false,
templateParameters: {
version,
},
template: require.resolve('./public/index.ejs'),
filename: 'index.html',
},
]);
config.plugin('preview').use(HtmlWebpackPlugin, [
{
inject: false,
templateParameters: {},
template: require.resolve('./public/preview.html'),
filename: 'preview.html',
},
]);
});
};