# 自定义控件前端2.0开发概述
本文档仅适用于协同版本为V8.0&CAP4.5及以上版本的CAP4表单.
V8.0&CAP4.5前版本的自定义控件前端没有提供统一规范,在实际开发过程基本上是自行发挥,"借鉴"已开发的工程,开发门槛较高,开发者不知如何下手,同时也暴露了一些比较低级的错误。针对这些问题,提出了自定义控件前端2.0规范,定义自定义控件前端的基本生命周期、事件、校验接口等。
自定义控件前端2.0确定了以下内容:
- 注册自定义控件统一接口
- 确定了自定义控件基类,明确了控件的生命周期、事件、API
- 规范基于csdk开放API来操作自定义控件、表单及进行数据通信
- 提供了Promise支持(csdk已经注入polyfill),建议异步操作都使用Promise
# 1. 启用自定义控件2.0
自定义控件2.0在每个控件上增加了一个version
属性,version
设为'2.0'即代表启用自定义控件2.0版本。
# 2. 自定义控件2.0生命周期
自定义控件生命周期大致分为下载、安装、渲染、更新、销毁等过程。
- 下载: 表单根据接口返回的控件定义信息
customFieldInfo
下载自定义控件的主js资源及国际化文件 - 安装: 资源下载完毕后调用控件定义的安装脚本(install)处理控件的初始化、业务逻辑等
- 渲染: 当表单渲染到该自定义控件时,自定义控件的渲染方法被调用
- 更新: 当控件数据发生变化时,自定义控件的更新方法被调用
- 销毁: 当控件被表单主动销毁时,自定义控件的销毁方法被调用
详见下图
# 3. 注册自定义控件
用csdk.component.register(uuid, factory)
申明自定义控件
- uuid: 自定义控件的唯一标识,建议使用
单词+uuid
实现,保证全局唯一及可读性 - factory: 自定义控件的具体实现,返回结构参照下图
csdk.component.register('myWidget-12345678', function () {
return {
....
}
});
自定义控件的基本代码结构如下
# 4. 生命周期钩子及API详细说明
下面对自定义控件的生命周期方法详述。
# - type
申明自定义控件实现的类型,可选值raw和vue, 当前版本仅支持raw。
- raw: 原生js实现
- vue: vue组件实现
# - plugin.install(context)
自定义控件资源下载完毕后调用plugin.install(contxt)执行安装脚本,一些常见的业务场景:
- 加载控件使用到的其他资源,如js、css、图片等
- 按次、按量计费的控件,超量超次控件不可使用,在install期间校验
- 从服务器读取控件的相关业务配置
参数/返回值说明:
@param {Object} context {package: '自定义控件控件包地址'},可用于加载包内的资源
@return Promise | undefined | Any
- install方法返回Promise,则表单会等待异步操作完成后才开始渲染自定义控件。
- install方法返回undefined, 表示操作完成。
- install方法返回其他值,表示在安装中遇到错误,无法继续渲染(比如付费服务的调用次数用完)。
示例:
// 没有异步,操作成功
plugin: {
install: function (context) {
// 异步操作返回Promise,示例检查接口调用次数是否用完
return new Promise(function (resolve) {
ajax('/xyz/validateApi', {
success: function(res) {
if (res.count <= 0) return; // 次数用完
resolve();
}
})
})
// 安装脚本出错
try {
a.b(); // 模拟报错
} catch (ex) {
return ex || 'unknow error';
}
// 返回undefined,表示没有异步操作且成功
return;
}
}
# - plugin.requiredAssert(fieldData)
控件必填校验逻辑,由开发者根据业务需要自行实现,默认校验字段的value是否有值
参数/返回值说明:
@param {Object} fieldData: 自定义控件对象
@return Boolean
# - plugin.fieldLengthAssert(fieldData)
控件长度校验,由开发者根据业务需要自行实现,默认校验通过
参数/返回值说明:
@param {Object} fieldData: 自定义控件对象
@return Boolean
# - plugin.validAssert(fieldData)
控件自定义场景校验,由开发者根据业务需要自行实现,默认校验通过
参数/返回值说明:
@param {Object} fieldData: 自定义控件对象
@return Boolean
# - implement.init(context, container)
控件初始化渲染,由开发者根据自身业务实现控件的渲染,事件绑定等,该方法必须实现
参数/返回值说明:
@param {Object} context 初始化渲染上下文参数
@param {HTMLElement} container 控件渲染的容器元素
@return Promise | Any 如果返回Promise, 则控件渲染完成事件会等待promise完成后触发
context参数说明
option: {
uuid: '', // 由表单生成唯一标识,用于识别控件实例,进行数据通信
scope: '', // 所在表单视图作用域,用于区分包含视图引用(视图嵌套)场景
fieldId: '', // 控件的数据域id
recordId: '', // 明细行数据id
tableName: '', // 明细表名
container: HTMLElement // 容器元素
}
示例:
init: function (context, container) {
console.log('init ' + this.$data.display)
var ctx = this;
var el = document.createElement('div');
el.style.cssText = 'padding: 10px 5px; color: white; background: gray';
el.innerHTML = this.$t('cap.form.loading'); // 国际化
setTimeout(function () {
el.innerHTML = 'test ' + ctx.$data.value;
}, 1000);
container.appendChild(el);
this.$el = el;
// 绑定事件
this.$on(this.$el, 'tap', function () {
// 更新数据
ctx.$set({
value: 'event changed ' + Date.now()
});
});
return new Promise(function (resolve) {
// 模拟异步渲染
setTimeout(function () {
this.$el.innerHTML = 'async rendering';
resolve();
}, 1000);
});
}
# - implement.update()
当控件数据发生变化时,会触发该方法,由开发者实现渲染更新
示例:
update: function () {
this.$el.innerHTML = 'updated at ' + Date.now() + '\n,new value is: ' + this.$data.value;
}
# - implement.destroy()
在控件被销毁前调用,由开发实现需要清理的事件、数据等
示例:
destroy: function () {
console.log('destroy ' + this.$data.display)
this.$el = null;
}
# - implement.beforeSave()
在表单保存时调用,由开发者实现当前控件需要在保存前的业务处理
参数说明:
@return Promise | Any 如果返回Promise,则表单会等待异步操作完成继续提交
注1: 由于交互问题,移动端轻表单模式只支持调用主表中的自定义控件该方法
注2: 由于数据分页,只支持调用在页面渲染好的(即可见)控件的该方法
注3: 除非特殊需要,尽可能减少这种场景设计
示例:
beforeSave: function () {
console.log('beforeSave ' + this.$data.display);
return new Promise((resolve) => {
// do sth cost 2 seconds
setTimeout(resolve, 2000);
});
}
# - implement.afterSave()
表单提交后调用该方法,由于保存后页面会关闭或者刷新,只建议实现同步调用
示例:
afterSave: function () {
console.log('Saved');
}
# - $t(i18nKey, replacer)
获取国际化词条
fI18nData['cap.form.mywidget.chineseDate'] = '{0}年{1}月';
this.$t('cap.form.mywidget.chineseDate', ['2020', '4']);
# - $set(data)
更新当前控件数据
示例:
data = {
value: 'value', // 控件的值
display: 'showValue', // 控件的显示值
auth: 'auth', // 控件的权限
atts: Object, // 待定,尚未完全支持
placeholder: 'placeHolder' // 输入框占位符
};
this.$set({
value: 'newValue',
display: 'newShowValue',
auth: 'browse'
})
# - $on(el, type, listener) 和 $on(type, listener)
控件事件绑定,支持绑定dom事件和控件自定义事件,使用方式如下:
- $on(el, type, listener) : 绑定dom事件
- $on(type, listener) : 绑定控件自定义事件
调用this.$on绑定的事件,在控件销毁时,会被自动销毁,开发者无须关注
# - $emit(type, data)
控件触发自定义事件
# 5. 自定义控件事件
EVENT_RENDERED: 自定义控件渲染完,需开发者保证
EVENT_UPDATED: 自定义控件更新完成
EVENT_DESTROYED: 自定义控件销毁
示例:
csdk.event.on(csdk.component.EVENT_RENDERED, function(evt) {
console.log('component rendered', evt);
});
# 6. 与表单、其他控件交互通信
与自定义控件1.0版本相比,2.0版本只在初始化提供必要参数,1.0版本中提供的一些其他数据不再传入。如需要获取表单数据、获取其他控件数据、更新表单、更新其他控件(包括自定义控件自身)、监听数据变化等请使用表单提供的csdk开发套件。csdk (opens new window).开发套件提供了一套PC和移动一致的API及事件,可实现大部分代码重用。
csdk相关文档见:
csdk API接口 (opens new window)
csdk 事件接口 (opens new window)
csdk 钩子 (opens new window)
End
快速跳转
- 自定义控件前端2.0开发概述
- 1. 启用自定义控件2.0
- 2. 自定义控件2.0生命周期
- 3. 注册自定义控件
- 4. 生命周期钩子及API详细说明
- - type
- - plugin.install(context)
- - plugin.requiredAssert(fieldData)
- - plugin.fieldLengthAssert(fieldData)
- - plugin.validAssert(fieldData)
- - implement.init(context, container)
- - implement.update()
- - implement.destroy()
- - implement.beforeSave()
- - implement.afterSave()
- - $t(i18nKey, replacer)
- - $set(data)
- - $on(el, type, listener) 和 $on(type, listener)
- - $emit(type, data)
- 5. 自定义控件事件
- 6. 与表单、其他控件交互通信