文 / 景朝霞
來源公號 / 朝霞的光影筆記
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]