# 新建编辑页JS插件
表单js插件可以非常容易地、无侵入地扩展表单功能。
新建编辑页JS插件包含以下扩展场景:
- 修改视图展示(自定义字段组件、自定义表单和从对象表格按钮、修改字段的视图状态)
- 控制表单流程(渲染表单、保存数据、数据校验、计算等)
- 拦截业务行为(表单按钮点击、字段值变更、从对象按钮点击等)
# 扩展钩子
# entry
用法:
该钩子用来匹配字段,指定哪些字段可以被插件重新定义。需要配合 render
使用。
参数:
context: Object
:字段的上下文环境field: Object
:字段描述信息
示例:
// 通过字段api_name判断
export default {
entry(context, field) {
return field.api_name === 'field_bbbb__c';
}
}
// 通过字段类型判断
export default {
entry(context, field) {
return field.type === 'text';
}
}
# render
用法:
视图渲染函数,定义如何渲染匹配到的字段。字段初次渲染和表单数据模型值发生变更,都会触发该钩子执行。需要配合 entry
使用。
参数:
context: Object
:字段的上下文环境field: Object
:字段描述信息value: *
:字段的值wrapper: Object
:渲染的容器DOM
返回:
可以返回渲染后的DOM字符串或者DOM对象,也可以不返回。
示例:
// 返回dom对象
export default {
render(context, field, value) {
var vm = new Vue({
render: h => h('div', 'hello fxiaoke')
}).$mount();
return vm.$el;
}
}
// 不返回结果
export default {
render(context, field, value, wrapper) {
var vm = new Vue({
render: h => h('div', 'hello fxiaoke')
}).$mount();
wrapper.appendChild(vm.$el);
}
}
# beforeRender
用法:
beforeRender发生在解析数据之后,渲染视图之前。
参数:
context: Object
:字段的上下文环境
返回:
promise: Promise
:无需传递数据。如果不返回,则阻塞后续的流程。
示例:
export default {
...
beforeRender(context) {
// todo what you want
return new Promise(function() {
resolve()
});
},
...
}
# rendered
用法:
rendered发生在渲染视图之后。
参数:
context: Object
:字段的上下文环境
返回:
promise: Promise
:无需传递数据。如果不返回,则阻塞后续的流程。
示例:
export default {
...
rendered(context) {
// todo what you want
return new Promise(function() {
resolve()
});
},
...
}
# beforeSubmit
用法:
beforeSubmit发生在保存数据之前。
参数:
context: Object
:字段的上下文环境postData: Object
:表单保存时需要提交的数据
返回:
promise: Promise
:promise的值为处理后的数据。如果不返回,则阻塞后续的流程。
示例:
export default {
...
beforeSubmit: function(context, postData) {
// todo what you want
return new Promise(resolve => {
resolve(postData)
});
},
...
}
# getTitle
用法:
该钩子用来定义表单标题。
参数:
context: Object
:字段的上下文环境data: Object
:数据data.isEdit: Boolean
:是否是编辑
返回:
title: String
:表单组件的标题。
示例:
export default {
...
getTitle(context, opts) {
return opts.isEdit ? '编辑' : '新建';
},
...
}
# getButtons
用法:
该钩子用来重置表单的按钮。
参数:
context: Object
:字段的上下文环境
返回:
buttons: Array|Object
:定义按钮的修改规则。如果返回数组,则为新增按钮。如果返回对象,则定义按钮的增删改。
示例:
...
getButtons(context) {
return [{
action: 'form_button_1',
label: '自定义按钮1',
callback(ct) {
alert('form_button_1');
}
},{
action: 'form_button_2',
label: '自定义按钮2'
}]
},
// or
getButtons(context) {
return {
add: [{
action: 'form_button_1',
label: '自定义按钮1',
callback(ct) {
alert('form_button_1');
}
},{
action: 'form_button_2',
label: '自定义按钮2'
}],
reset: [{
action: 'form_button_3',
label: '自定义按钮3'
}],
del: ['cancel']
}
},
...
说明:
- add:定义新增按钮
- reset:定义重置按钮,可以重置按钮名称和点击行为
- del:删除预制按钮
# getMdButtons
用法:
该钩子用来重置从对象表格的按钮。
参数:
context: Object
:字段的上下文环境detailObjectApiName: String
:从对象的apiName
返回:
buttons: Object
:定义按钮的修改规则。
示例:
...
getMdButtons(context, detailObjectApiName) {
return return detailObjectApiName === 'object_5Xnrv__c' ? {
add: [{
label: '从对象按钮(添加数据)',
action: 'test_handle_1',
callBack() {
console.log('getMdButtons.button');
context.addDetailData('object_n8q24__c', 'default__c', [{
name: 123,
}])
}
}],
reset: {
Single_Add: {
label: '添加数据'
}
}
}:{
// del: ['Single_Add'],
'default__c': {
add: [{
label: '从对象按钮(添加)(无callback)',
action: 'addMdData'
},{
label: '从对象按钮(删除)(无callback)',
action: 'delMdData'
},{
label: '从对象按钮(修改)(无callback)',
action: 'updateMdData'
}]
}
}
},
...
说明:
- add:声明新增按钮
- reset:声明重置按钮,可以重置按钮名称和点击行为
- del:声明删除的按钮
- default__c:声明给哪个业务类型定义按钮
# getMdOperateButtons
用法:
该钩子用来重置从对象单行数据的操作按钮。
参数:
context: Object
:字段的上下文环境detailObjectApiName: String
:从对象的apiName
返回:
buttons: Array
:定义按钮的修改规则。
示例:
...
getMdOperateButtons(context, detailObjectApiName) {
console.log('getMdOperateButtons', arguments);
return detailObjectApiName === 'object_n8q24__c' ? [function() {
return {
add: [{
label: '自定义操作按钮',
action: 'test_handle_3',
callBack() {
console.log('test_handle_3');
}
}]
}
}] : []
}
...
说明:
- add:声明新增按钮
- 单行操作按钮仅支持增加按钮,不支持删除、定义重置按钮
# getMdBatchButtons
用法:
该钩子用来重置从对象表格批量操作按钮。
参数:
context: Object
:字段的上下文环境detailObjectApiName: String
:从对象的apiName
返回:
buttons: Object
:定义按钮的修改规则。
示例:
...
getMdBatchButtons(context, detailObjectApiName) {
console.log('getMdBatchButtons', arguments);
return detailObjectApiName === 'object_n8q24__c' ? {
add: [{
label: '自定义批量按钮',
action: 'test_handle_4',
callBack() {
alert(arguments)
}
}]
} : {}
},
...
说明:
- add:声明新增按钮
- 批量操作按钮仅支持增加按钮,不支持删除、定义重置按钮
# 以上三个从对象按钮重置规则说明
说明:
方法 | 说明 | 参数 | 参数内参数格式及说明 | crm表格从对象按钮格式 |
---|---|---|---|---|
getMdButtons.add | 添加按钮 | Array | Object:label、action、callback(可选) | Object:label、action、name |
getMdButtons.reset | 修改按钮 | Object | Object(name):label | Object:label、action、name |
getMdButtons.del | 删除按钮 | Array | String(对应按钮的name) | Object:label、action、name |
getMdOperateButtons | 仅支持添加按钮 | Object | Object:label、action、callback(可选) | Object:label、action |
getMdBatchButtons | 仅支持添加按钮 | Object | Object:label、action、callback(可选) | Object:label、action |
# getMdColumnRenders
用法:
该钩子用来定义从对象上的布局规则。
参数:
context: Object
:字段的上下文环境detailObjectApiName: String
:从对象的apiName
返回:
rules: Object
:从对象布局规则
示例:
export default {
...
getMdColumnRenders(context, detailObjectApiName) {
const rules = {
object_adlkjd__c: {
field_dlkjdd__c: {
depend_fields: ['field_aaaaa__c', 'field_bbbbb__c'],
render(val, data) {
return '<div>...</div>'
}
}
}
}
return rules;
},
...
}
说明:
- object_adlkjd__c:为从对象的apiName
- field_dlkjdd__c:从对象的字段
- depend_fields:声明field_dlkjdd__c受哪些字段影响
- render:定义展示的内容
# getMdImportConfig
用法:
该钩子用来定义导入从对象的相关配置:格式化导入的数据。
参数:
context: Object
:字段的上下文环境
返回:
config: Object
:导入从对象配置filterExcelDatas: Function
:处理从excel读取的数据filtersMappingFields: Function
:声明哪些字段不允许被导入
示例:
export default {
...
getMdImportConfig() {
return {
filterExcelDatas(dataList) {
return dataList.filter(item => !!item.owner);
},
filtersMappingFields() {
return ['field_axie__c', 'owner'];
}
}
}
...
}
# registerListener
用法:
该方法发生在表单渲染之后,开发者可以用来注册表单事件。
注册事件:
- addFormClickListeners
- addFieldValueChangeListeners
- addMdFieldValueChangeListeners
- addMdClickListeners
示例:
- 监听表单按钮点击
export default {
...
registerListener() {
this.addFormClickListeners('submitAndCreate');
this.addFormClickListeners('form_button_2');
}
...
}
说明:可以监听自定义按钮,也可以监听预设按钮。参数格式为 按钮action
- 监听主对象值变更
export default {
...
registerListener() {
this.addFieldValueChangeListeners('name');
this.addFieldValueChangeListeners('field_dax23__c');
}
...
}
说明:参数格式为 字段apiName
- 监听从对像值变更
export default {
...
registerListener() {
this.addMdFieldValueChangeListeners('object_n8q24__c.field_1z0oZ__c');
this.addMdFieldValueChangeListeners('object_n8q24__c.default__c.field_1z0oZ__c');
}
...
}
说明:参数格式为 从对象apiName.业务类型.字段apiName
或 从对象apiName.字段apiName
- 监听从对象按钮点击
export default {
...
registerListener() {
// 自定义按钮
this.addMdClickListeners('object_dQ8rr__c.addMdData');
this.addMdClickListeners('object_dQ8rr__c.delMdData');
this.addMdClickListeners('object_dQ8rr__c.updateMdData');
// 添加一行
this.addMdClickListeners('object_dQ8rr__c.singleAdd');
// 删除
this.addMdClickListeners('object_dQ8rr__c.delRow');
}
...
}
说明:可以监听自定义按钮,也可以监听预设按钮;参数格式为 从对象apiName.业务类型.按钮action
或 从对象apiName.按钮action
。
# click
用法:
该方法发生在按钮点击时,用来处理点击事件。
参数:
- 绑定表单按钮点击事件
context: Object
:字段的上下文环境e: Object
:事件对象eventTarget: String
:按钮apiNameobjectApiName: String
:对象apiNameeventName: String
:固定值 - clicktype: String
:固定值 - form
- 绑定从对象表单点击事件
context: Object
:字段的上下文环境e: Object
:事件对象eventTarget: String
:按钮apiNameobjectApiName: String
:对象apiNameeventName: String
:固定值 - clicktype: String
:固定值 - md
next: Function
: singleAdd、delRow按钮会传入此方法。执行后,会继续原有的业务操作。
# change
用法:
该方法发生在字段值变化时,用来处理值变更事件。
参数:
- 绑定主对象字段值变更事件
context: Object
:字段的上下文环境e: Object
:事件对象objectApiName: String
:对象apiNamefieldApiName: String
:字段apiNameeventName: String
:固定值 - changetype: String
:固定值 - dataobjectType: String
:固定值 - mastervalue: String
:字段变更后的值oldValue: String
:字段变更前的值
- 绑定从对象字段值变更事件
context: Object
:字段的上下文环境e: Object
:事件对象objectApiName: String
:从对象apiNamerecordType: String
:从对象业务类型fieldApiName: String
:字段apiNameeventName: String
:固定值 - changetype: String
:固定值 - dataobjectType: String
:固定值 - detailvalue: String
:字段变更后的值
# context
# getDescribe()
用法:
该方法返回当前对象的对象描述信息。
返回:
describe: Object
:对象的描述信息api_name: String
:对象的apiNamedisplay_name: String
:对象的名称fields: Object
:对象的所有字段
示例:
const describe = context.getDescribe();
console.log(describe.api_name);
console.log(describe.fields);
# getFields()
用法:
返回该对象下的所有字段。
示例:
const fields = context.getFields();
console.log(fields.name);
console.log(fields.owner);
# getDetailData()
用法:
该方法返回从对象的对象描述信息。
参数:
detailObjectApiName: String
:从对象的apiName
示例:
const describe = context.getDetailData('object_dQ8rr__c');
console.log(describe.api_name);
console.log(describe.fields);
# getAllDetailDescribes()
用法:
该方法返回所有从对象的对象描述信息。
示例:
const describes = context.getAllDetailDescribes();
describes.forEach(describe => {
console.log(describe);
})
# getData()
用法:
该方法返回主对象的数据。
参数:
fieldApiName: String
:字段的apiName(可选)
示例:
const data = context.getData();
console.log(data.name);
console.log(data.owner);
const nameValue = context.getData('name');
console.log(nameValue);
# setData()
用法:
设置数据。
参数:
fieldApiName: String | Object
:字段的apiNamevalue: *
:字段的值
示例:
context.setData('name', 'fxiaoke');
context.setData({
'name': 'fxiaoke',
'owner': [1000]
});
# getDetailData()
用法:
获取某个从对象某个业务类型的数据
参数:
apiName: String
:对象的apiNamerecordType: String
:对象的业务类型(可选)
返回:
固定apiName(固定业务类型)下的从对象数据
示例:
let data = context.getDetailData('object_ad3xs__c');
let data1 = context.getDetailData('object_ad3xs__c', 'default__c');
# getAllDetailDatas()
用法:
获取所有从对象的数据。
返回:
获取所有从对象数据。
示例:
const data = context.getAllDetailDatas();
console.log(data);
# addDetailData()
用法:
新增从对象数据。支持給多个对象的多个业务类型同时添加数据。
示例:
context.addDetailData('object_R9tuj__c', 'default__c', [{
name: 'hello fxiaoke',
}])
context.addDetailData('object_R9tuj__c', [{
record_type: 'default__c',
name: 'hello fxiaoke',
}])
context.addDetailData([{
record_type: 'default__c',
name: 'hello fxiaoke',
object_describe_api_name: 'object_R9tuj__c'
}])
# updateDetailData()
用法:
更新从对象数据。支持給多个对象的多个业务类型同时更新数据。
示例:
context.updateDetailData('object_R9tuj__c', 'default__c', [{
name: 'hello fxiaoke',
rowId: '' //必传
}])
context.updateDetailData('object_R9tuj__c', [{
record_type: 'default__c',
name: 'hello fxiaoke',
rowId: '' //必传
}])
context.updateDetailData([{
record_type: 'default__c',
name: 'hello fxiaoke',
object_describe_api_name: 'object_R9tuj__c',
rowId: '' //必传
}])
# deleteDetailData()
用法:
删除从对象数据。支持給多个对象的多个业务类型同时删除数据。
示例:
context.deleteDetailData('object_R9tuj__c', 'default__c', [{
name: 'hello fxiaoke',
rowId: '' //必传
}])
context.deleteDetailData('object_R9tuj__c', [{
record_type: 'default__c',
name: 'hello fxiaoke',
rowId: '' //必传
}])
context.deleteDetailData([{
record_type: 'default__c',
name: 'hello fxiaoke',
object_describe_api_name: 'object_R9tuj__c',
rowId: '' //必传
}])
# setDetailRowStyle()
用法:
设置从对象行样式。
示例:
constext.setDetailRowStyle('object_dQ8rr__c','default__c','1669894692997240', 'font-size: 20px;')
constext.setDetailRowStyle('object_dQ8rr__c','default__c',['1669894692997240','1669894692997241'], 'background-color: red;')
constext.setDetailRowStyle([{
record_type: 'default__c',
object_describe_api_name: 'object_R9tuj__c',
rowId: '1669894692997240'
}], 'background-color: red;')
# 常见示例
# 自定义字段
需求:
目前,百分比字段是以 数字+百分号
的样式呈现在用户界面上,为了提升该字段的体验,需要以进度条的交互形式来展示。
分析:
- 如何扩展字段组件
- 表单设置字段值时,如何传递给自定义的字段组件
- 字段组件状态变更后,字段值如何传递给表单
代码:
let vm = null;
// 自定义字段具体实现
const Progress = Vue.extend({
props: {
value: String
},
data() {
return {
percentage: this.value ? this.value * 1 : 0,
colors: [
{color: '#f56c6c', percentage: 20},
{color: '#e6a23c', percentage: 40},
{color: '#5cb87a', percentage: 60},
{color: '#1989fa', percentage: 80},
{color: '#6f7ad3', percentage: 100}
]
};
},
methods: {
setValue(val) {
this.percentage = val;
},
//增加进度
increase() {
this.percentage += 10;
if (this.percentage > 100) {
this.percentage = 100;
}
this.$emit('change', `${this.percentage}`);
},
//降低进度
decrease() {
this.percentage -= 10;
if (this.percentage < 0) {
this.percentage = 0;
}
this.$emit('change', `${this.percentage}`);
}
},
render(h) {
return (
<div>
<fx-progress type="dashboard" percentage={this.percentage} color={this.colors}></fx-progress>
<div>
<fx-button-group>
<fx-button icon="el-icon-minus" on-click={this.decrease}></fx-button>
<fx-button icon="el-icon-plus" on-click={this.increase}></fx-button>
</fx-button-group>
</div>
</div>
)
}
});
// 导出插件
export default {
entry(context, field) {
return field.type === 'percentile';
},
render(context, field, value) {
if (field.type === 'percentile') {
if (!vm) {
vm = new Progress({
propsData: {
value // 初始值传递给自定义字段组件
}
}).$mount();
vm.$on('change', (val) => {
context.setData(field.api_name, val) // 自定义字段组件值变更后,通知表单修改数据模型
});
return vm.$el;
}else {
vm.setValue(value); // 表单数据模型值变更后,通知自定义字段修改值
}
}
},
beforeDestroy() {
if (vm) {
vm.$destroy();
vm = null;
}
}
}
# 处理从对象按钮
需求:
删除从对象需要满足某些条件才允许删除;新增从对象单条数据操作按钮,点击后可以自动更新当前数据。
分析:
- 如何拦截从对象删除
- 如何新增数据操作按钮以及如何注册该按钮的点击事件
代码:
export default {
// 定义从对象object_dQ8rr__c的单条操作按钮
getMdOperateButtons(context, detailObjectApiName) {
return detailObjectApiName === 'object_dQ8rr__c' ? [function() {
return {
add: [{
label: '自定义操作-自动更新数据',
action: 'single_data_btn',
callBack(data) {
// todo what you want
data.name = 'test';
context.updateDetailData(data);
}
}]
}
}] : []
},
// 注册点击事件
registerListener() {
this.addMdClickListeners('object_dQ8rr__c.delRow'); // 注册删除按钮点击事件
},
// 处理点击事件
click(context, e, next) {
if (e.type === 'md') {
if (e.objectApiName === 'object_dQ8rr__c') {
if (e.eventTarget === 'delRow') {
// 执行拦截逻辑
setTimeout(() => {
next();
}, 3000)
}
}
}
}
}
# 表单提醒
需求:
如果从对象的值不符合要求(主属性包含test),则修改从对象的背景色为红色,突出显示。
分析:
- 如何监听从对象的值变更
- 如何修改从对象的背景色
代码:
export default {
registerListener() {
this.addMdFieldValueChangeListeners('object_n8q24__c.name'); // 注册字段值变更事件
},
change(context, e) {
if(e.type === 'data') {
if (e.objectType === 'detail') {
const data = e.data;
if (e.value.indexOf('error') > -1) {
context.setDetailRowStyle(data.object_describe_api_name, data.record_type, [data.rowId], 'background-color: #ea7569!important;')
}else {
context.setDetailRowStyle(data.object_describe_api_name, data.record_type, [data.rowId], '');
}
}
}
}
}