上一篇文章講了如何開始使用阿裡低代碼引擎 low-engine,以及如何在引擎 demo 中引用自定義元件,本篇将基于 vant 和 antd 封裝一些低代碼元件,帶領大家熟悉自定義元件的封裝和注意事項。
建立低代碼的元件庫初始化項目參考文檔:lowcode-engine.cn/docV2/funcv…
上篇文章位址:
阿裡低代碼引擎 lowcode-engine 使用詳解 - 開發自定義元件并內建
一、 Container
構造頁面時需要給其他元件一個容器來包裹,先用 vant 的 Card 元件來封裝我們的容器元件 Container。
src/components
目錄下建立
Container
檔案夾,再建立
Container.tsx
和
index.tsx
檔案
Container.tsx
import * as React from 'react';
import {createElement} from 'react';
import {Card} from 'react-vant';
import './index.scss'
export interface ContainerProps {
title?: string;
style?: 'object'
direction?: 'row' | 'column'
}
/**
* 由 Card 組成的 container 容器
* @param title
* @param children
* @param otherProps
* @constructor
*/
const JContainer: React.FC<ContainerProps> = ({title, children, direction = 'column', style = {}, ...otherProps}) => {
const _style = style || {} as any;
_style.flexDirection = direction;
const _otherProps = otherProps || {} as any;
_otherProps.style = _style;
return (
<Card>
{title && <Card.Header>{title}</Card.Header>}
<Card.Body>
<div className={'container-wrapper'} {..._otherProps}>
{children}
</div>
</Card.Body>
</Card>
)
}
export default JContainer
複制代碼
複制
direction
屬性是控制 Container 裡面元素的排列方式,對應 flex 布局的
flex-direction
屬性。
index.tsx
import Container from './Container'
export type {ContainerProps} from './Container'
export default Container;
複制代碼
複制
然後在
src/index.tsx
導出
export type {ContainerProps} from './components/container'
export {default as Container} from './components/container'
複制代碼
複制
運作指令
npm run lowcode:dev
會看到跟
src
同級的目錄
lowcode
目錄下多了個
container
檔案夾,裡面有個
meta.ts
檔案,這是根據代碼生成的元件描述檔案,在拖拽使用這個元件時,低代碼引擎根據這個描述檔案來解析元件。
import { ComponentMetadata, Snippet } from '@alilc/lowcode-types';
const ContainerMeta: ComponentMetadata = {
"componentName": "Container",
"title": "Container",
"docUrl": "",
"screenshot": "",
"devMode": "proCode",
"npm": {
"package": "mini-elements",
"version": "0.1.1",
"exportName": "Container",
"main": "src/index.tsx",
"destructuring": true,
"subName": ""
},
"configure": {
"props": [
{
"title": {
"label": {
"type": "i18n",
"en-US": "title",
"zh-CN": "title"
}
},
"name": "title",
"setter": {
"componentName": "StringSetter",
"isRequired": true,
"initialValue": ""
}
}
],
"supports": {
"style": true
},
"component": {}
}
};
const snippets: Snippet[] = [
{
"title": "Container",
"screenshot": "",
"schema": {
"componentName": "Container",
"props": {}
}
}
];
export default {
...ContainerMeta,
snippets
};
複制代碼
複制
預設生成的描述檔案,可能不能滿足需求,需要拓展。
想要更多自定義配置,有兩種方式:
- 在代碼中寫
自動生成propTypes
- 手動配置
定義好元件的 Props 之後,運作
npm run lowcode:dev
指令會根據目前定義的 props 自動生成描述檔案,基本類型自動生成的描述一般沒啥問題,但如果是複雜對象可能會描述不太準确。
注意這裡有個坑,隻有第一次運作以上指令才會自動生成描述檔案,如果這個元件的描述檔案已經存在,我們又修改了元件,再次運作指令則不會将新增的屬性追加進描述檔案中,換句話說以後都需要手動配置了。
有個小技巧可以減輕工作量,如果你沒有手動改過配置檔案,那修改元件源碼後,每次運作前把描述檔案删掉,就可以按照最新的 Props 自動生成新的描述檔案了。
但是如果按下面的方式手動配置過描述檔案,不建議删掉重新生成,之前手動配置的都會丢失。
更改
lowcode/contianer/meta.ts
,想要它成為一個容器,在
component
對象下設定 isContainer 即可。
如果想添加新的屬性,或者代碼中元件的 props 中定義的屬性沒有顯示出來,則需要手動新增 props。
direction
屬性想要枚舉值,隻有
row
和
column
兩個屬性值。查詢支援的設定器,發現
RadioGroupSetter
可以滿足需求,按照定義寫我們自己的屬性和設定器
{
name: 'direction',
description: '内容的排列方向',
setter: {
componentName: 'RadioGroupSetter',
initialValue: 'column',
props: {
options: [
'column',
'row'
],
}
}
}
複制代碼
複制
完整的定義如下:
import {ComponentMetadata, Snippet} from '@alilc/lowcode-types';
const ContainerMeta: ComponentMetadata = {
"componentName": "Container",
"title": "Container",
"docUrl": "",
"screenshot": "",
"devMode": "procode",
"npm": {
"package": "mini-elements",
"version": "0.1.1",
"exportName": "Container",
"main": "src/index.tsx",
"destructuring": true,
"subName": ""
},
"configure": {
"props": [
{
"title": {
"label": {
"type": "i18n",
"en-US": "title",
"zh-CN": "title"
}
},
"name": "title",
"setter": {
"componentName": "StringSetter",
"isRequired": false,
"initialValue": ""
}
},
{
name: 'direction',
description: '内容的排列方向',
setter: {
componentName: 'RadioGroupSetter',
initialValue: 'column',
props: {
options: [
'column',
'row'
],
}
}
}
],
"supports": {
"style": true
},
"component": {
isContainer: true,
nestingRule: {
// 允許拖入的元件白名單
// childWhitelist: ['ColorfulButton', 'Button'],
// 同理也可以設定該元件允許被拖入哪些父元件裡
// parentWhitelist: ['Tab'],
},
}
}
};
const snippets: Snippet[] = [
{
"title": "Container",
"screenshot": "",
"schema": {
"componentName": "Container",
"props": {}
}
}
];
export default {
...ContainerMeta,
snippets
};
複制代碼
複制
效果如圖,可配置一個 title 屬性,如果有值則渲染 Header,沒有就不渲染。
還可選擇
direction
的值,預設 column。
裡面可以拖入其他元件,但僅限白名單裡的元件。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwIjNx8CX39CXy8CXycXZpZVZnFWbp9DciV2duIWM1QWZ4YTZ5QmN1U2YhRjZ0UWM3UGM0kjNzEjNhJTZvwFO0UjMxQjNtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.webp)
二、Panel 元件
先看下效果圖,Panel 元件包含兩部分:Title 和 Content,重點突出 content 的内容。
右邊可配置的屬性為:
- title: 标題
- content:内容,一般為數字
- flex: flex 布局下所占的份數,同 css 的 flex 屬性,預設 1
在
src/components
下建立
panel
目錄,并建立
Panel.tsx
、
index.tsx
和
index.scss
三個檔案
// Panel.tsx
import React, { createElement } from 'react'
import './index.scss'
export interface PanelProps {
title: string;
content: string;
flex: number;
}
const Panel: React.FC<PanelProps> = ({title, content, flex = 1, children, ...otherProps}) => {
const _otherProps = otherProps || {} as any;
// @ts-ignore
_otherProps.style = otherProps.style || {} as any
_otherProps.style.flex = flex;
return (
<div className={'panel'} {...otherProps}>
<div className={'title'}>{title || 'Panel标題'}</div>
<div className={'content'}>{content || 'Panel内容'}</div>
</div>
)
}
export default Panel
// index.tsx
import Panel from './Panel'
export type {PanelProps} from './Panel'
export default Panel;
// index.scss
@import "./src/variables";
.panel {
display: flex;
flex-direction: column;
.title {
font-size: 12px;
color: $text-minor;
}
.content {
font-size: 28px;
font-weight: 500;
color: $text-main;
}
}
複制代碼
複制
同樣需要修改生成的
lowcode/panel/meta.ts
檔案,一般來說如果隻是修改可配置的屬性,隻需改
configure.props
屬性即可。
import { ComponentMetadata, Snippet } from '@alilc/lowcode-types';
const PanelMeta: ComponentMetadata = {
"componentName": "Panel",
"title": "Panel",
"docUrl": "",
"screenshot": "",
"devMode": "procode",
"npm": {
"package": "mini-elements",
"version": "0.1.1",
"exportName": "Panel",
"main": "src/index.tsx",
"destructuring": true,
"subName": ""
},
"configure": {
"props": [
{
"title": {
"label": {
"type": "i18n",
"en-US": "title",
"zh-CN": "title"
}
},
"name": "title",
"setter": {
"componentName": "StringSetter",
"isRequired": true,
"initialValue": ""
}
},
{
"title": {
"label": {
"type": "i18n",
"en-US": "content",
"zh-CN": "content"
}
},
"name": "content",
setter: {
componentName: 'MixedSetter',
props: {
setters: [
'StringSetter',
'VariableSetter',
],
},
}
},
{
name: 'flex',
setter: {
componentName: 'NumberSetter',
initialValue: 1
}
}
],
"supports": {
"style": true
},
"component": {}
}
};
const snippets: Snippet[] = [
{
"title": "Panel",
"screenshot": "",
"schema": {
"componentName": "Panel",
"props": {}
}
}
];
export default {
...PanelMeta,
snippets
};
複制代碼
複制
三、Table 元件
在各種元件中,Table 元件是最複雜的了。要把 Table 封裝好,會使用到幾乎所有的設定器。
由于時間關系,先隻暴露
dataSource
和
columns
屬性,通過
columns
屬性,我們将學會如何使用
ArraySetter
動态設定數組。通過
dataSource
屬性,我們将學會使用
MixedSetter
使屬性支援多種設定方式。
本元件基于 antd 的 Table 擴充。
在
src/components
目錄下建立
Table
檔案夾,然後建立
Table.tsx
和
index.ts
檔案
import React, {createElement} from 'react'
import Table, {ColumnsType} from "antd/lib/table";
export interface JTableProps {
columns: ColumnsType;
dataSource: any[];
}
const JTable: React.FC<JTableProps> = ({columns, dataSource}) => {
// 資料處理,防止字段為空
const _columns = columns?.map((col, index) => {
if (!col) {
return {
dataIndex: `${index}`,
title: '列名'
}
}
const {dataIndex, title} = col as any;
return {
dataIndex: dataIndex || `${index}`,
title: title || '列名'
}
})
return (
<Table
dataSource={dataSource}
columns={_columns}
/>
);
}
export default JTable
複制代碼
複制
import Table, {JTableProps} from './Table'
export type {JTableProps}
export default Table;
複制代碼
複制
别忘了在
src/index.tsx
上注冊元件,否則看不到效果。
export type {JTableProps} from './components/Table';
export {default as Table} from './components/Table'
複制代碼
複制
運作
npm run lowcode:dev
,會在
根目錄/lowcode
下生成
table
檔案夾,裡面的
meta.ts
就是元件的描述檔案。
由于我們暴露出的屬性
dataSource
和
columns
是複雜結構,自動生成的描述不能滿足需求,是以手動更改描述檔案:
import { ComponentMetadata, Snippet } from '@alilc/lowcode-types';
const TableMeta: ComponentMetadata = {
"componentName": "Table",
"title": "Table",
"docUrl": "",
"screenshot": "",
"devMode": "procode",
"npm": {
"package": "mini-elements",
"version": "0.1.6",
"exportName": "Table",
"main": "src/index.tsx",
"destructuring": true,
"subName": ""
},
"configure": {
"props": [
{
"title": {
"label": {
"type": "i18n",
"en-US": "資料列",
"zh-CN": "資料列"
}
},
"name": "columns",
"setter": {
"componentName": "ArraySetter",
"props": {
"itemSetter": {
"componentName": "ObjectSetter",
"isRequired": false,
"props": {
config: {
items: [
{
"name": "dataIndex",
"setter": {
"componentName": "StringSetter",
"isRequired": true,
"initialValue": "id"
}
},
{
"name": "title",
"setter": {
"componentName": "StringSetter",
"isRequired": true,
"initialValue": "列名"
}
},
]
}
},
}
},
"isRequired": true,
initialValue: [
{
dataIndex: 'id',
title: 'ID'
},
{
dataIndex: 'name',
title: '姓名'
},
{
dataIndex: 'age',
title: '年齡'
},
]
},
},
{
"name": "dataSource",
setter: {
componentName: 'MixedSetter',
props: {
setters: [
'JsonSetter',
'VariableSetter',
],
},
}
}
],
"supports": {
"style": true
},
"component": {}
}
};
const snippets: Snippet[] = [
{
"title": "Table",
"screenshot": "",
"schema": {
"componentName": "Table",
"props": {}
}
}
];
export default {
...TableMeta,
snippets
};
複制代碼
複制
效果如圖:
columns
是一個數組,我們可以自由的加減列,是以需要用官方提供的
ArraySetter
,使用文檔 點這裡。每一個 item 都是一個
ObjectSetter
,說實話結構還挺複雜的。
dataSource
支援綁定資料源和直接寫 json,是以使用
MixedSetter
。
四、坑點
如果你用的是 antd 元件庫,那麼會遇到個大坑。
項目中用到了
@ant-design/icons
時,比如在一個元件中引用了某個 icon,會導緻元件渲染報錯
原因是找不到這個圖示元件,查一下加載的 js 資源,發現并沒有加載
ant-design/icons
沒想到自家的元件庫竟然不完全支援!測試發現其他的元件庫,像 vant、tea 等都沒有這個問題。
暫時還沒想到在元件庫層面的解決辦法,還沒找到手動注入
ant-design/icons
的入口。
但是在 demo 中用元件庫的時候,找到了解決方案。官方 demo 有個
assets.json
,這裡定義了引用的資源,我們可以手動把 icon 添加進去,這樣在項目運作時,
ant-design/icons
就會正常加載,項目也就不報錯了。
這種方法有個缺點,在元件庫封裝過程中,其實是看不到效果的,因為渲染不出來。隻有在具體使用元件庫的時候,才會渲染出來,調試不友善。
總結
其實自定義封裝元件,總結一下就三步:
- 在
檔案夾下建立元件的檔案夾,寫邏輯代碼,定義需要對外暴露的 props 。src/components
- 在
中注冊元件。不注冊的話頁面上看不到。根目錄/index.tsx
- 運作
指令,會在npm run lowcode:dev
目錄下自動生成元件的描述檔案根目錄/lowcode
,簡單類型的 props 比如 string、bool 一般沒啥問題,如果是複雜類型,比如複雜對象、數組,自動生成的描述可能不是我們想要的,這時需要手動改描述檔案。meta.ts
前兩步我們都比較熟悉,重點主要在第三步改描述檔案。在頁面上對元件進行拖拽、配置時,支援的操作都是由描述檔案定義的。描述檔案的重點是設定器,一個屬性支援怎樣的互動,是可以輸入文字,還是下拉框,還是可增删的數組,都是由設定器定義的。
設定器
Setter
的文檔在 這裡,裡面包含了所有官方提供的
Setter
。據平時的經驗看,官方的設定器能滿足 90% 的日常需求。當然還支援自定義 Setter,這部分我還沒研究,可以檢視官方文檔。
官方的 demo 又更新了,新增了 antd 所有元件的支援,如果沒有特殊需求,直接用官方提供的元件省時省力。
這個低代碼引擎感覺還是在原型階段,官方的文檔、demo 會時不時更新,及時關注可能會有意外收獲。