文 / 景朝霞
来源公号 / 朝霞的光影笔记
ID / zhaoxiajingjing
图 / 本身画
❥❥❥❥点个赞,让我知道你来过~❥❥❥❥
【前情提要】javascript
【iview】php
上个月,用iview的Table组件作合并行的效果,认真的读了下那块的源码,收获颇多。vue
△14.1iview的Table组件的行/列合并java
https://github.com/view-desig...
△14.2在table.vue的props对象里面定义属性node
它使用在这:
getChildNode (h, data, nodes) { // ...CODE if (data.children && data.children.length) { data.children.forEach((row, index) => { let $tds = []; this.columns.forEach((column, colIndex) => { // => 在循环每一列时,判断当前行/列是否须要展现"合并行"的属性 // => this.showWithSpan() 方法返回一个布尔值 // => 是:进入判断体 if (this.showWithSpan(row, column, index, colIndex)) { // ...CODE const $td = h('td', { class: this.alignCls(column, row), // => 设置td的attrs属性,在vue里面写入DOM属性用 atrrs // => this.getSpan() 方法返回rowspan、colspan的值 attrs: this.getSpan(row, column, index, colIndex) }, [$tableCell]); // ...CODE } }); }); } // ...CODE }
△table-body.vue设置rowspan/colspangit
/** * 获取span的值 * @param {object} row * @param {object} column * @param {number} rowIndex * @param {number} columnIndex * * @return {object} 返回一个对象 */ getSpan (row, column, rowIndex, columnIndex) { // => 把父级的spanMethod函数的堆内存16进制地址赋值给fn // => fn就是传进来的那个函数了 const fn = this.$parent.spanMethod; // => 判断fn是否为函数 // => 是函数:一些操做 // => 不是函数:则返回一个 {}对象 if (typeof fn === 'function') { // => fn是函数,则调用该函数,传递实参集合,把函数的返回结果赋值给result const result = fn({ row, column, rowIndex, columnIndex }); // => 初始值rowspan/colspan都默认为1 let rowspan = 1; let colspan = 1; // => 前面截图:spanMethod能够返回一个数组/对象 // => 判断拿到的result是否为数组 // => 分别获取到用户设置的rowspan/colspan的值 if (Array.isArray(result)) { rowspan = result[0]; colspan = result[1]; } else if (typeof result === 'object') { rowspan = result.rowspan; colspan = result.colspan; } // => 把结果返回去 return { rowspan, colspan }; } else { return {}; } }, /** * 展现行/列合并 * @param {object} row 当前行 * @param {object} column 当前列 * @param {number} rowIndex 当前行索引 * @param {number} columnIndex 当前列索引 * * @return {boolean} 返回一个布尔值:有,true 没有 false */ showWithSpan (row, column, rowIndex, columnIndex) { // => 调用 this.getSpan() 方法,把返回结果赋值给常量 result const result = this.getSpan(row, column, rowIndex, columnIndex); // => 在result里面rowspan/colspan任意一个为0,则取反->true // => 最后的结果是返回一个boolean值 return !(('rowspan' in result && result.rowspan === 0) || ('colspan' in result && result.colspan === 0)); };
△table-body.vue处理rowspan/colspangithub
!(('rowspan' in result && result.rowspan === 0) || ('colspan' in result && result.colspan === 0))
编程
(1)运算符优先级(数字越大优先级越高):api
()
圆括号20
!
逻辑非16
in
11
===
全等号10
&&
逻辑与6
||
逻辑或5
(2)A||B
A为真,则返回A;A不为真,则返回B
A&&B
A为真,则返回B;A不为真,则返回A
(3)prop in obj
in判断对象中是否有属性prop
(4)==
等号:只须要判断值是否相等,若是两边数据类型不一致,先转换数据类型,再进行判断
===
全等号:严格判断,既判断数据类型也判断值,都相等才为TRUE
(5)为FALSE的5种状况:''
空字符串、null
、undefined
、0
、NaN
(1)行/列合并是在版本4.0.0加上的——保持原有代码的基础上升级:使用了spanMethod方法传参
(2)行/列合并控制table的td属性rowspan、colspan,须要指定哪行哪列:数组/对象均可以
(3)在收到指定行/列时,就须要判断是否为函数,是函数才能够被调用;函数的返回结果数组/对象拿到对应的值。
在开发中,遇到的问题:
简单一句:保证原有的代码没问题,还要同时能升级保证2+棵树的展现啰嗦的解释,能够跳过:
基于iview的Form组件的动态增减表单项功能(https://www.iviewui.com/compo...)在实际应用中作了一个动态生成搜索条件的form表单的组件
CustomSearch
,包含表单项:Input输入框、DatePicker日期选择器 、Select 选择器、Checkbox多选框、Cascader级联选择、Tree树。其中,Tree树组件是基于jQuery的zTree树插件进行封装。Tree组件所须要的数据是每一个业务场景里自行传入的数据进行渲染的,以各个参数传参过去的,如:
:treeData=""
渲染树的数组。在以前的需求中,搜索条件的tree只有一棵树就知足了。最初设计CustomSearch组件与Tree组件渲染时,就很繁琐,只按照一棵树来渲染了。
在最新的需求里,须要两棵树的搜索条件了,动态请求回来的数据是能够把DOM渲染出来的。可是对于如何传参进去渲染不一样的tree又如何对于点选的搜索条件进行获取,须要在原有的基础上进行扩展并兼容原有代码。
△14.3 需求:在搜索条件展现2+棵树
搜索条件的数据是封装在CustomSearch这个组件里面,可是Tree的数据须要单独请求,再放进去渲染的。
△14.4原有的组件只支持一棵树的展现
如今须要改为支持2+棵树,同时此种方法也支持1棵树的渲染,兼容以前的写法,这个在其余地方用的不少,不能影响别人的使用。
△14.5业务的CustomSearch高级搜索组件里面
MOCK模拟的接口地址:
form表单动态数据的接口[ https://www.fastmock.site/moc...]所属学院组织树[https://www.fastmock.site/moc...]
/** * 设置tree的初始化数据的芳芳 * @param [Object] treeJSON 展现tree的form项 * @param [Array] treeKeys 展现tree的form项的key, * @returns {Object} 再把处理好的数据还回去 */ treeMethod(treeJSON, treeKeys) { // 给每个Tree添加初始化信息 treeKeys.forEach((item, index) => { // treeParamsCustom 是一个对象,因此拿到它的堆内存地址便可 let treeParams = treeJSON[item].formItemClass['treeParamsCustom']; // 初始化:treeData数据为空、默认不展现 this.$set(treeParams, 'treeData', []); this.$set(treeParams, 'isShowTree', false); // 请求接口 this.getTreeData([url], treeParams); }); return treeJSON; }, /** * 获取Tree的数据 * @param url 请求接口 * @param treeParams 须要设置的属性 */ getTreeData(url, treeParams) { treeParams.isShowTree = false; _this.$http.get(url).then((response) => { let {data: {data: {treeData=[]}}} = response; if (response.processStatus) { treeParams.treeData = treeData; treeParams.isShowTree = true; } }, () => { treeParams.isShowTree = false; console.log('error'); }); },
△应用:treeMethod方法,放在vue文件的methods对象里面
//获取isChecked属性为true的数据 getShowData(rows){ let _this = this; _this.items=[]; for(let i=0;i<rows.length;i++){ let isChecked = rows[i].customClass.isChecked; let title = rows[i].title; if(isChecked){ //当title为空时,通常都是跟前面的搜索内容相关联的,若是以前的不展现,则没有title的也不展现在搜索中 if(!title && rows[i-1] && rows[i-1].customClass.isChecked){ _this.items.push(rows[i]); } //若是是第一个则不与前面的搜索内容关联 if(!title && !rows[i-1]){ _this.items.push(rows[i]); } //正常的搜索内容,都会带title, if(title){ _this.items.push(rows[i]); } } } /* 以上代码主要是在把请求回来的数据处理成Form组件须要的格式 https://www.iviewui.com/components/form#DTZJBDX 在此时,把异步请求回来的Tree的数据放进来便可 */ if (typeof this.treeMethod === 'function') { /** * by jing_zhaoxia@sina.com * 把tree的信息放在form表单里面渲染 * 初始化须要$set */ let treeJSON = {}; let treeKeys = []; // => 筛选出 treeJSON和treeKeys // => 设置一个对象做为命名空间,把用户操做的数据都放进去,这样在提交保存时候,能够统一删除掉便可 _this.items.forEach((row, index) => { let {formItemClass: {formItemType}, key} = row; if (formItemType === 'Tree') { treeKeys.push(key); treeJSON[key] = row; // 补一个自定义的tree参数,后面提交时候能够删掉 this.$set(treeJSON[key].formItemClass, 'treeParamsCustom', {}); } }); // => 把Tree的数据一一到对应的items里面 this.getTreeParams(treeJSON, treeKeys) .then(result => { if (typeof result !== 'undefined' && ({}).toString.call(result) === '[object Object]') { _this.items = _this.items.map((item, index) => { if (treeKeys.includes(item.key)) { item = result[item.key]; } return item; }); } }) .catch(err => { console.log(err); }); } }, // => 异步请求,这里使用 Promise来处理 getTreeParams(treeJSON = {}, treeKeys = []) { return new Promise((resolve, reject) => { const fn = this.treeMethod; let result = treeJSON; if (typeof fn === 'function') { result = fn(treeJSON, treeKeys); if (({}).toString.call(result) === '[object Object]') { resolve(result); } } resolve(result); }); },
△设置form的items项,放在vue文件的methods对象里面
△14.6兼容之前的代码
/** * 设置Tree组件须要的参数,兼容以前的写法 * @param item 每一条form-item * @param constructor 当前值的数据类型 * @param key 须要的key */ setTreeParams(item, constructor, key){ if (item.formItemClass['treeParamsCustom'] !== undefined){ let value = item.formItemClass['treeParamsCustom'][key]; return ({}).toString.call(value) === `[object ${constructor}]` ? value : this[key]; } return this[key]; },
△兼容之前的代码,放在vue文件的methods对象里面
跟着jquery大佬学编程思想,尚未想好怎么写成文字描述的,先贴一个分享地址吧~
[ https://github.com/jingzhaoxi...]
运算符优先级[ https://developer.mozilla.org...]iviewui的Table组件[https://www.iviewui.com/compo...]
iviewui的Form组件[https://www.iviewui.com/compo...]
iviewui源码[https://github.com/view-desig...]
jQuery的zTree[http://www.treejs.cn/v3/api.php]