电脑桌面
添加蚂蚁七词文库到电脑桌面
安装后可以在桌面快捷访问

自定义控件开发进阶篇

来源:金蝶云社区作者:金蝶2024-09-233

自定义控件开发进阶篇

# 1 用户场景 业务场景越来越多,开发人员不满足于自定义控件写一些静态组件或者页面,因此自定义控件需要获取后端返回来的数据,并且能够实现前后端交互全流程。 # 2 功能介绍 使用`java`插件或者`KDE`脚本插件,给自定义控件传输业务数据,`java`插件的写法和`KDE`脚本大同小异。该例子会使用`KDE`脚本插件 # 3 控件对象 设计时对象 ```java kd.bos.ext.metadata.form.control.CustomControlAp ``` 运行时对象 ```java kd.bos.ext.form.control.CustomControl ``` 动态创建自定义控件时,配置项和控件方案只能在设计时配置,运行时自定义控件可以在插件里调用setData方法给自定义控件传输业务数据。 # 4 操作步骤 ## 4.1 插件赋值 ### 4.1.1 新建KS脚本 * 开发平台找到对应自定义控件单据所在的**应用**,点击打开`KDE`编辑器 ![image.webp](/download/01002a7f433ac9554b139071385c5f71d2d3.webp) * 在编辑器中找到对应的单据页面,鼠标右键选择菜单"**新建插件脚本**" * 这里我们将新建的插件脚本文件命名为"**sendganttdata.ks**" ![image.webp](/download/0100e8384be520b94ff7a126b9b4a3270ed0.webp) ### 4.1.2 开发KS脚本 将下面代码复制到上面创建的插件脚本中,并修改对应的值 ```js var plugin = new FormPlugin({ afterBindData : function(e){ // getControl中传入的是自定义控件的标识(key),可在设计器里面查看,并不是方案id(schemaId) var customcontrol = this.getView().getControl('helloworld'); // 这里是你要给前端发送的数据, var data = { text: '你好,自定义控件' } //调用该自定义控件的setData方法赋值 customcontrol.setData(data) } }); ``` ![image.webp](/download/0100c3a8acf09b914eeeb02a8c8434bf0cc3.webp) ### 4.1.3 检查返回数据 返回"**设计器**"里面的对应单据页面,点击"**预览**"按钮查看页面 确认新建的插件已经"启用",可通过单据页面的"**插件**"属性查看是否已启用 ![image.webp](/download/01006093e59ad9f14e4b92603a8adca8bc63.webp) ![image.webp](/download/0100fbcc96f27194472db49caad47734f18f.webp) 上图可以看到"Network"面板里面就是刚才在`sendganttdata.ks`里面定义返回来的数据 ### 4.1.4 控件获取数据 修改自定义控件`index.js`里的`initFunc`函数,可以从`props`中获取得到后端传过来数据`text`,示例代码如下: ```js var initFunc = function(model, props) { // KDApi.loadFile可以通过路径加载js或css文件,并且在html文件头生成script或者link标签,第一个参数是路径,第二个参数是model,第三个参数是加载完成后执行的回调函数 KDApi.loadFile('./css/helloworld.css', model, function() { // 通过路径去获取html字符串,第一个参数是路径,第二个参数是model,第三个参数是HTML模板中变量的值 var text = props.data && props.data.text || [] KDApi.getTemplateStringByFilePath('./html/helloworld.html', model, { text: text }).then(function(result) { model.dom.innerHTML = result }) }) } ``` ![image.webp](/download/0100861ee643210f4b50a84d947381002362.webp) 通过上面例子,我们完成了自定义控件插件赋值的方法。 但是在上面的例子中,自定义控件可以获取后端返回来的数据,解决了纯静态类的自定义控件需求,但是如果自定义控件更加复杂,需要有点击事件,编辑等需求,自定义控件要和后端插件实现主动通信。 因此,自定义控件和插件需要如何编写?接下来为你介绍。 ## 4.2 前后端交互 在这一小节里,会通过前端的点击事件给后端发请求,后端插件接收到这个请求后弹出一个提示框,这样即可完成前后端完整的交互。 ### 4.2.1 前端发送请求 * 在`index.js`里,声明`initEvent`函数,监听点击事件,并执行`model.invoke`方法给后端发送请求,代码示例如下: ```js var initEvent = function(model, props){ //内置了jquery对象,可直接使用$ $('.helloworld', model.dom).click(function(){ // model.invoke,用于给后端发送请求,第一个参数是事件名,可自定义;第二个参数是发送给后端的数据,可以是任意类型 model.invoke('click', 'Hello World!') }) } ``` ### 4.2.2 DOM绑定事件 * 在`index.js`里的`initFunc`函数中,通过`initEvent`给`DOM`绑定操作事件 * PC端支持使用jQuery库绑定事件,initEvent方法实现请参考4.2.1章节 ```js var initFunc = function(model, props) { // KDApi.loadFile可以通过路径加载js或css文件,并且在html文件头生成script或者link标签,第一个参数是路径,第二个参数是model,第三个参数是加载完成后执行的回调函数 KDApi.loadFile('./css/helloworld.css', model, function() { // 后端插件通过setData传给前端的数据,前端可以通过props.data去获取 var text = props.data && props.data.text || '' // 通过路径去获取html字符串,第一个参数是路径,第二个参数是model,第三个参数是HTML模板中变量的值 KDApi.getTemplateStringByFilePath('./html/helloworld.html', model, { text: text }).then(function(result) { model.dom.innerHTML = result // 绑定DOM事件 initEvent(model, props) }) }) } ``` ### 4.2.3 后端处理请求 * 在脚本插件的`customEvent`方法里(即插件中重写customEvent方法),处理前端发送过来的请求 ```js var plugin = new FormPlugin({ afterBindData : function(e){ // getControl中传入的是控件的标识(key)不是方案id(schemaId) var customcontrol = this.getView().getControl('helloworld'); var data = { text: '你好,自定义控件' } customcontrol.setData(data) }, customEvent: function(e) { // 设计器上自定义控件的标识 var key = e.getKey() // 前端通过model.invoke传给后端的数据 var args = e.getEventArgs() // 前端通过model.invoke定义的事件名 var eventName = e.getEventName() this.getView().showMessage('key: ' + key + ';eventName: ' + eventName + ';args: ' + args) } }); ``` ### 4.2.4 保存预览 保存脚本后,在设计器中点击"**预览**"按钮,效果如下: ![image.webp](/download/0100f8231d0b78a64ab9a9574052642ce98b.webp) 至此,一个完整的前后端交互的例子完成了! # 5 代码示例 ## 5.1 前端示例 自定义控件默认是集成了jquery,简单控件可直接使用其进行开发即可,如果你希望通过使用其他框架来实现如React、Vue等,也是支持的,以下将以热门框架React、Vue为例,在例子中使用前端打包工具webpack,开发完后,编译,将控件目录下的lang文件夹、css文件夹、index.js、index.js.map打成zip包上传即可。 ### 5.1.1 vue 在此例子中打包入口为main.js,输出index.js和index.css,所以之前在index.js里写的代码可以挪到main.js中 ```js // 在main.js上通过import引入Vue库和自己写的Vue组件库 import Vue from 'vue' import Steps from './components/steps.vue' import eventBus from '../../../../../../util/eventBus' /** * Vue实例在setHtml方法中声明,初始化执行init的时候就能够创建 * 声明Vue实例对象时,在其挂载完毕的生命周期里声明一个订阅,用于订阅update方法中发布的消息,从而更新实例数据 * update方法中,发布一个消息,让Vue实例接收消息,更新数据 * 在Vue实例的destroyed中,结束订阅 * 注意loadFile中index.css的引入路径,因为webpack打包后将其放在了css文件夹里,所以路径是./css/index.css */ (function (KDApi) { function MyComponent (model) { this._setModel(model) } MyComponent.prototype = { _setModel: function (model) { this.model = model }, init: function (props) { console.log('-----init', this.model.style, props) setHtml(this.model, props) }, update: function (props) { console.log('-----update', this.model, props) eventBus.pub(this.model, 'update', props) }, destoryed: function () { console.log('-----destoryed', this.model) } } const setHtml = (model, props) => { KDApi.loadFile('./css/index.css', model, () => { const { invoke, dom } = model const { data } = props const activeI = data ? data.avtiveIndex : -1 new Vue({ el: dom, template: '<Steps :invoke="invoke" :activeInd="activeIndex" :model="model" :getLangMsg="getLangMsg" />', components: { Steps }, data: { activeIndex: activeI, model: model }, mounted () { const self = this this.updateSub = eventBus.sub(model, 'update', (props) => { const { data } = props self.activeIndex = data ? data.activeIndex : -1 }) }, destroyed () { eventBus.unsub(this.updateSub) }, methods: { invoke: (eventName, args) => { invoke(eventName, args) }, getLangMsg: (key) => { return KDApi.getLangMsg(model, key) } } }) }) } // 注册自定义组件 KDApi.register('stepsVue', MyComponent, { isMulLang: true }) })(window.KDApi) ``` ### 5.1.2 react 在此例子中打包入口为main.js,输出index.js和index.css,所以之前在index.js里写的代码可以挪到main.js中 ```js import React from 'react' import ReactDOM from 'react-dom' import TodoList from './components/TodoList' import eventBus from '../../../../../../util/eventBus' /** * 在setHtml中声明Root类,使用ReactDOM.render将其渲染在model.dom中 * 在Root类的componentDidMount里,声明一个订阅,用于接收后端更新发过来的消息,从而去更新组件 * 在update里,发布一个消息,当后端插件给自定义控件传递新数据时,就能将消息发布给Root * 在Root类的componentWillUnmount里,取消订阅 * 在destoryed里,使用ReactDOM.unmountComponentAtNode卸载Root * 注意loadFile中index.css的引入路径,因为webpack打包后将其放在了css文件夹里,所以路径是./css/index.css */ (function (KDApi) { function MyComponent (model) { this._setModel(model) } MyComponent.prototype = { _setModel: function (model) { this.model = model }, init: function (props) { console.log('-----init', this.model.style, props) setHtml(this.model, props) }, update: function (props) { console.log('-----update', this.model, props) eventBus.pub(this.model, 'update', props) }, destoryed: function () { console.log('-----destoryed', this.model) ReactDOM.unmountComponentAtNode(this.model.dom) } } var setHtml = function (model, primaryProps) { KDApi.loadFile('./css/index.css', model, () => { class Root extends React.Component { constructor(props) { super(props) this.state = { customProps: props.customProps, model: props.model } } componentDidMount () { const { model } = this.state this.updateSub = eventBus.sub(model, 'update', (updateProps) => { this.setState({ customProps: updateProps}) }) } shouldComponentUpdate () { } componentWillUnmount () { eventBus.unsub(this.updateSub) } render () { const { customProps, model } = this.state return ( <TodoList model={model} customProps={customProps} /> ) } } ReactDOM.render(<Root model={model} customProps={primaryProps} />, model.dom) }) } // 注册自定义组件 KDApi.register('todolistreact', MyComponent) })(window.KDApi) ``` ### 5.1.3 jquery 实现一个控件方案id为"dellabel"的自定义控件 ``` // index.js (function (KDApi, $) { // 构造函数 function MyComponent (model) { this._setModel(model) } var themeColor MyComponent.prototype = { // 绑定model _setModel: function (model) { this.model = model }, // 生命周期:初始化 init: function (props) { console.log('-----init', this.model, pro

自定义控件开发进阶篇

# 1 用户场景业务场景越来越多,开发人员不满足于自定义控件写一些静态组件或者页面,因此自定义控件需要获取后端返回来的数据,并且能够...
点击下载文档文档为doc格式

声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。

确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息
QQ群
  • 答案:my7c点击这里加入QQ群
支持邮箱
微信
  • 微信