跳到主要内容

自定义组件开发

1. 简介​

一个可用于搭建的组件需要具备的基本能力: 组件运行时 + 属性配置能力 + 逻辑编排能力 。

Alt text

基于 前端低代码 组件开发规范,可以开发出强大的组件,包括编辑、I/O 通信、类型系统、Slots、多语言、权限、基于 Schema 的父子组件联动(表单容器等场景)、响应式等各个方面

  1. 支持视图组件、逻辑组件等类型,视图组件支持 Vue、React、React Native 等不同技术栈;
  2. 支持可组合、可扩展、基于区域的声明式编辑器,编辑器中除常规编辑器之外,还包含了一些高级编辑器,例如代码编辑器、富文本编辑器等(详见附件中的内置编辑器类型清单);
  3. 布局方面,组件支持流式、绝对定位、固定定位,基于环境(env.canvasType 手机、Pad、PC 等)的响应式布局等方式;
  4. 支持具名插槽,作用域插槽,动态插槽等,插槽中的布局可自定义,具名插槽应用于组件基于规则的组合,例如商品列表与商品卡片的组合,作用域插槽提供了 I/O 编排能力;
  5. 组件支持 Inputs 与 Outputs(简称 I/O ),I/O 基于数据流图,在框图的扩展下可实现图灵完备,是组件在逻辑层面联动的重要能力;
  6. 可扩展 API,通过基于场景的 env 注入方式实现扩展,例如可以注入埋点上报、jsbridge 等能力;
  7. 多语言、权限声明式控制、埋点方案、主题方案等;
  8. AIGC 支持等;

2. 如何创建第一个组件库​

2.1 安装开发环境​

https://marketplace.visualstudio.com/items?itemName=MyBricks.MyBricks

或在 vscode 中通过「扩展」在应用商店中搜索扩展「MyBricks」,安装该扩展即可

2.2 初始化组件库​

点击 VSCode 界面左侧活动栏上的 「MyBricks 图标」 ,新建一个组件库

Alt text

2.3 ⚙️ 组件库配置【重要勿忘】​

配置根目录下的 mybricks.json 文件,主要修改以下几个部分

{
/* 组件发布相关信息 */
"domain": "http://example.com", // 此处修改为对应的 MyBricks 平台地址
"userName": "xxx@gmail.com", // 此处修改为开发者在平台注册的账号,可在平台左下角查看并复制

/* 是否开启 px 到 vw 的转换,移动端H5使用,PC端勿开启 */
"pxToVw": {}, // 添加该行内容,即可开启转换,默认基准值为 375px

/* 组件库信息 */
"componentType": "PC", // 组件库类型,PC请填写PC、H5请填写H5
"namespace": "test-normal-lib", // 组件库的唯一标识,必填!类比npm中package.json的name,修改了就是另一个组件库了
"comAry": [ // 组件库列表配置
"./src/button/com.json", // 组件入口文件相对路径
"./src/comA/com.json",
"./src/comB/com.json"
],
"tags": "vue" // 如果使用vue组件开发,必须填写vue
}

如何获取 userName?

Alt text

2.4 启动调试环境​

当项目下有 *.mybricks.json 配置文件时,就能够看到 MYBRICKS DEVELOP 面板,点击调试,选择需要调试的配置文件即可

Alt text

点击 「调试」 按钮,等待编译完成后会打开浏览器,接下来就可以开始开发组件了

Alt text

2.5 发布组件到物料中心​

与 调试 同理,点击 「发布」 按钮,选择相应的配置文件, 请确保 2.3 的配置配置完成

选择 发布至物料中心选项 ,等待上传完成即可

Alt text

2.6 🎉 使用组件​

打开应用,添加组件库

Alt text

选中刚刚发布的组件库即可直接使用

Alt text

3. 如何为组件添加编辑器​

打开前面初始化好的组件库代码,进入 src/button 目录

打开 editors.tsx 文件

Alt text

修改组件初始化的配置

  //修改组件初始化时候的宽高
'@init'({ style }) {
style.width = 80;
style.height = 50;
},
//配置组件支持修改的属性(宽、高)
'@resize': {
options: ['width', 'height']
},

将组件的一些数据写活,支持由 前端低代码 编辑器进行修改

  ':root': [
{
items: [
{
title: '文字标题',
type: 'text',
value: {
get({ data }) {
return data.text;
},
set({ data }, value: string) {
data.text = value;
}
}
},
{
title: '样式',
type: 'style',
options: {
defaultOpen: true,
plugins: ['border', 'font']
},
value: {
get: ({ data }) => {
return data.style;
},
set: ({ data }, value) => {
data.style = value;
}
}
}
]
}
]

Alt text

在 runtime.tsx 中使用 data.text,和编辑器修改的 data.text 进行关联

Alt text

Alt text

至此我们就完成了一个拥有配置能力的组件开发。

4. 深入组件​

组件分为 UI 组件 和 逻辑组件 两种类型,其中 UI 组件支持多种框架,比如 Vue、React、Taro 或其他自定义版本 等。

Alt text

4.1 不同框架的组件运行时区别​

渲染器会通过 props 为组件提供增强能力,包括但不限于 id, title, data, inputs, outputs, slots, env。我们看到 Vue 和 React 组件略有一个差别就是 Vue 组件中想要获取这些能力比 React 组件多了一层 m,这是因为我们为了避免 this.data 和 Vue 的 data 在书写的时候引起歧义。

Vue 组件、React 组件或其他技术栈组件唯一的不同点在于运行时文件的实现,例如 runtime.vue、runtime.tsx。

Vue

{
...,
"runtime": "./runtime.vue", // 如果是 vue 组件,runtime 所引用的文件路径需要为 .vue 文件
...
}
<template>
<div class="button">{{ m.data.text }}</div>
</template>

<script>
export default {
props: ["m"],
}
</script>

React

{
...,
"runtime": "./runtime.tsx", // 如果是 react 组件,runtime 所引用的文件路径需要为 .tsx 文件
...
}
import React from "react";

export default function ({id, title, data, inputs, outputs, slots, env}) {
return (
<div className="button">{data.text}</div>
);
}

4.2 编辑器​

编辑器可对组件进行编辑,包括但不限于配置组件的搭建时生命周期;修改组件 Prop 中的 data 属性值;注入组件样式等。

编辑器代码在组件运行时会被忽略,仅在搭建时会被引用。

Alt text

图例:编辑器为右侧绿框区域

编辑器的生效首先需要在 com.json 中声明。例:

{
...,
"editros": "./myEditors.tsx",
...
}

搭建时生命周期​

功能描述示例代码
@init 组件在拖入画布的时候触发函数
export default {  '@init'({ data, style, input, output, slot }){    style.width = "100%";    style.height = 60;  },  ...}
@resize 声明组件支持调整宽、高
export default {  '@resize': {    options: ['width', 'height']  },  ...}

区域选择能力​

我们通过下方的动图可以看到一个组件在被拖入画布之后,在点击组件的不同区域时,编辑器区域所渲染的编辑项会有所变化,该特性有助于将组件复杂的编辑项进行拆分,在点击某区域时,才会渲染对应区域的编辑项。

代码示例:

export default {
...,
// 通过 css selecotr 来声明区域即可
":root": {
items: [...全局相关编辑项声明]
},
".demo-a": {
title: "demo A",
items: [...A相关编辑项声明]
},
".demo-b": {
title: "demo B",
items: [...B相关编辑项声明]
},
};

编辑项联动​

我们通过下方的动图可以看到编辑项的渲染可以存在联动。

代码示例:

export default {
":root": {
items: [
{
title: "使用自定义文本",
type: "switch",
value: {
get({ data }) {
return data.useCustomText;
},
set({ data }, value) {
data.useCustomText = value;
},
},
},
{
ifVisible({ data }) {
return data.useCustomText;
},
title: "自定义文本",
type: "textinput",
value: {
get({ data }) {
return data.customText;
},
set({ data }, value) {
data.customText = value;
},
},
},
],
},
};

开发自定义编辑项​

引擎内置了多种编辑器类型,详见附录预置编辑器列表,如果预置编辑器无法满足需求,可以通过扩展自定义编辑器来实现个性化需求。

export default {
...
{
title: "自定义编辑项",
type: "editorRender", //自定义编辑器
options: {
render: ({ editConfig }) => {
return (<div onClick={() => {
//设置数据
editConfig.value.set("new value");
}}>当前数据:{ editConfig.value.get() }</div>);
}
},
value: {
get({data}){
return data.text;
},
set({data}, value){
data.text = value;
}
}
}
...
}

样式注入​

有两种方式注入样式,第一种就是基于通用的 style 编辑器类型来配置组件 prop 中的 data 值,第二种可以更加便捷,只需要添加配置项,无需关注渲染逻辑。

export default {
...
":root": {
style: [
title: "标题",
options: ["border", "background"], //支持哪些 css 配置
target: ".demo" //作用到哪个 css selector
]
}
...
}

options 支持的值有:font、padding、margin、size、border、background、shadow 等。

4.3 插槽​

基础插槽​

最常见的插槽,可以理解为具名插槽,它允许您在组件的 任意位置预留坑位 ,在搭建时可以拖入任意组件

Alt text

Step1: 在 com.json 文件声明插槽的信息

{
"title": "demo",
"namespace": "xxx",
...
"slots": [
{
"id": "content1", // 声明插槽的ID,待会runtime会用到
"title": "插槽1" // 声明插槽的名称,搭建时会展示出来
},
{
"id": "content2",
"title": "插槽2"
}
]
}

Step2: 在 runtime 中使用 slot

<template>
<div class="layout">
<div class="text">我是组件的title</div>
<div class="body">
<div>
<slot name="content1" />
</div>
<div>
<slot name="content2" />
</div>
</div>
<div class="text">我是组件的footer</div>
</div>
</template>

4.4 组件间通信​

施工中...

5. Github 组件/编辑库 资源​

PC 基础组件库

PC 通用组件库

H5 通用组件库(Vue 版)

通用编辑库

附录​

目录结构​

my-comlibs/
├── package.json //基础信息
├── mybricks.json
├── dev.mybricks.json //*.mybricks.json 文件,用于不同环境、不同阶段的发布
├── ...
└── src/
├── button/
│ ├── com.json //组件声明文件
│ └── runtime.tsx //react 组件运行时
├── text/
│ ├── com.json //组件声明文件
│ └── runtime.vue //vue 组件运行时
├── comB/
├── comC/
└── ...

组件库配置文件 mybricks.json​

{
/* 组件发布相关信息 */
"domain": "http://example.com", // 此处修改为对应的 前端低代码 apaas 平台地址
"userName": "xxx@gmail.com", // 此处修改为开发者在平台注册的账号,可在平台左下角查看并复制

/* 是否开启 px 到 vw 的转换,移动端H5使用,PC端勿开启 */
"pxToVw": {}, // 添加该行内容,即可开启转换,默认基准值为 375px

/* 组件库信息 */
"componentType": "PC", // 组件库类型,PC请填写PC、H5请填写H5
"namespace": "test-normal-lib", // 组件库的唯一标识,必填!类比npm中package.json的name,修改了就是另一个组件库了
"comAry": [ // 组件库列表配置
"./src/button/com.json", // 组件入口文件相对路径
"./src/comA/com.json",
"./src/comB/com.json"
],
"tags": "vue" // 如果使用vue组件开发,必须填写vue
}

组件声明文件说明​

属性说明类型必须默认值
title标题stringY-
namespace全局命名空间,组件的唯一标识string(可用 - _ . 作为分隔,如 mycompany.bu.name)Y-
author作者 IDstringY'anonymous'
author_name作者stringN'匿名作者'
version版本号( MyBricks 对于组件有严格的版本控制)VersionType(例:1.0.0)Y-
icon图标路径或地址path(例:./icon.svg) 或 URLY默认图标
runtime运行时path(例:./NormalButton.tsx)Y-
editors编辑项path(例:./editors.tsx)N-
datamodel 数据描述(用于组件作为预览及其他用途)path(例:./data.json)N-
inputs输入项数组{id:string(当前组件唯一), title:string, schema?:JSONSchema}[]N-
outputs输出项数组{id:string(当前组件唯一), title:string, schema?:JSONSchema}[]N-
slots插槽数组{id:string(当前组件唯一), title:string, scoped?:boolean}[]N-
description组件描述信息stringN-

预置(随引擎搭载)编辑器列表​

标题代码示例图例
按钮(button)
{  title: "demo",  type: "button",  value: {    set({ data }) {      // 无需返回值    },  },};
Alt text
文本(textinput)
{  title: "demo",  type: "textinput",  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  }};
Alt text
文本域(textarea)
{  title: "demo",  type: "TEXTAREA",  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  },};
Alt text
数字框(inputnumber)
{  title: "demo",  type: "inputnumber",  options: [    { title: "宽", width: 100 },    { title: "高", width: 100 },  ],  value: {    get({ data }) {      return [data.mysetting1,               data.mysetting2];    },    set({ data }, value) {      [data.mysetting1,        data.mysetting2] = value;    },  },};
Alt text
富文本(richtext)
{  title: "demo",  type: "richtext",  options: {    type: "h5",  },  value: {    get({ data }) {      return decodeURIComponent(        data.mysetting);    },    set({ data }, value) {      data.mysetting =         encodeURIComponent(value);    },  },};
Alt text
图片选择(imageselector)
{  title: "demo",  type: "IMAGESELECTOR",  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  },};
Alt text
单选(radio)
{  title: "demo",  type: "radio",  options: [    { label: "选项1", value: "1" },    { label: "选项2", value: "2" },    { label: "选项3", value: "3" },  ],  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  },};
Alt text
下拉框(select)
{  title: "demo",  type: "SELECT",  options: [    { label: "选项一", value: "1" },    { label: "选项二", value: "2" },    { label: "选项三", value: "3" },  ],  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  },};
Alt text
开关(switch)
{  title: "demo",  type: "switch",  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  },};
Alt text
滑块(slider)
{  title: "demo",  type: "slider",  options: {    max: 24,    min: 1,    steps: 1,  },  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting1 = value;    },  },};
Alt text
对象编辑器(map)
{  title: "demo",  type: "MAP",  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  },}
Alt text
数组编辑器(array)
{  title: "demo",  type: "ARRAY",  options: {    // 自定义标题渲染    getTitle(item, index) {      return (        
标题:{index}
); }, // 添加一项时的默认值 onAdd() { return { key1: "key1默认值", key2: "key2默认值", }; }, // 数组项 items: [ { title: "标题1", type: "text", // 编辑器类型 value: "key1",// 对象的 key }, { title: "标题2", type: "textarea", value: "key2", }, ], }, value: { get({ data }) { return data.mysetting; }, set({ data }, value) { data.mysetting = value; }, },}
Alt text
代码编辑器(code)
{  title: "demo",  type: "CODE",  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  },};
Alt text
颜色选择器(colorpicker)
{  title: "demo",  type: "colorpicker",  value: {    get({ data }) {      return data.mysetting;    },    set({ data }, value) {      data.mysetting = value;    },  },};
Alt text
事件(_event)
{  title: "demo",  type: "_event",  options: {    outputId: "myOutputId",  },};
Alt text

多端渲染​

Alt text