您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么使用vue el-tree實現懶加載數據和樹的過濾”,在日常操作中,相信很多人在怎么使用vue el-tree實現懶加載數據和樹的過濾問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用vue el-tree實現懶加載數據和樹的過濾”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
樹的樣式:
過濾效果:
過濾代碼實現:
1,如果這里的樹數據是全加載,即可使用element-ui中的設置,進行前端過濾。
element-ui對應的組件位置
<el-input placeholder="輸入關鍵字進行過濾" v-model="filterText"> </el-input> <el-tree class="filter-tree" :data="data" :props="defaultProps" default-expand-all :filter-node-method="filterNode" ref="tree"> </el-tree> // 監聽輸入框中的數據 watch: { filterText(val) { this.$refs.tree.filter(val); } }, methods: { filterNode(value, data) { if (!value) return true; return data.label.indexOf(value) !== -1; } },
2,如果這里的樹數據是懶加載,,需要使用后端的模糊加載,返回搜索到的樹的節點。
重要的是:filter-node-method=“filterNode”,這個屬性
<el-input placeholder="請輸入搜索內容" v-model="filterText" class="inputStyle" clearable> </el-input> <el-tree :data="treeData" node-key="id" :filter-node-method="filterNode" ref="dimTree" :props="treeDataDefaultProp" class="tree_Style" :expand-on-click-node="false" :load="loadNode" lazy ></el-tree> data(){ return { filterText: '', keyword:'', } } watch: { // 樹節點的過濾 filterText(val) { this.keyword = val this.getTreeData() } methods:{ // 將keyword傳入到接口中,從后端返回模糊匹配后的節點,然后賦值給樹綁定的數據變量,即可完成。 // 得到樹的列表 async getTreeData() { const param = { type: Number(this.cateTabActive), keyword: this.keyword }; const res = await this.$api.get('/api/category', param); if (res.code == 200) { this.treeData = res.info; } else { return false; } }, }
本文章項目項目全程使用Vue2和Element2!
懶加載:點擊節點時才進行該層數據的獲取。
注意:使用了懶加載之后,一般情況下就可以不用綁定:data。
懶加載需要再指定一個lazy和懶加載數據的方法:load:
<template> <el-tree :props="props" :load="loadNode" lazy></el-tree> </template> <script> export default { data() { return { props: { // 映射配置 label: 'name', // 將獲取數組中的name作為顯示節點(label)進行展示 children: 'zones', // 將獲取數組中的zones作為子節點(children)的展示 isLeaf: 'leaf' // 將獲取數組中的leaf作為判斷是否是葉子節點(即沒有子節點的最底層節點) }, }; }, methods: { loadNode(node, resolve) { // 懶加載數據時載入的方法,只會執行一次 if (node.level === 0) { // 初始的級數(最頂層) return resolve([{ name: 'region' }]); // 最頂層數據渲染為region } if (node.level > 1) return resolve([]); setTimeout(() => { const data = [{ name: 'leaf', leaf: true }, { name: 'zone' }]; resolve(data); }, 500); } } }; </script>
懶加載的方法會得到兩個參數,一個是獲取的當前節點(node)的信息(包括它的層級數據等);另一個是一個重新渲染當前節點下子節點的方法(resolve),它接收一個數組,該數組也會按照props中的映射關系,進行顯示。
注意:懶加載的方法(:load)在初始載入時執行一次,而后每次點擊節點前面的箭頭獲取子節點的時候再次觸發;即使初始載入的數據有變換也不會再觸發,點擊展開子節點后再次點擊收縮節點時也不會再觸發!!
由于懶加載是一級一級往下獲取,所以對每一級來說都要使用resolve來渲染它顯示的子節點,如果該節點下沒有顯示的內容,它則會一直轉圈,這個時候需要設置resolve返回一個空數組,這樣如果它沒有獲取到子節點的內容則會在轉圈之后顯示為空(并去掉前面的向下展開的箭頭),不會一直轉圈:
return resolve([]);
現實場景:可以在通過node取到每一層的id,根據這個id調用接口得到數據。再通過resolve進行回顯,回顯的數據為這個id的子節點
場景:由于用到樹形控件的地方很多,而且需要顯示的數據都不一樣,所以將樹形控件再封裝一層,然后根據外部組件傳來的不同參數,進行樹形圖的不同顯示。
思路:通過監聽外部傳入數據的變化,重新渲染樹,完成不同數據的顯示;但是:load只會初始加載一次并獲取當前綁定樹上node,如果后面監聽數據的時候再次調用loadTree是獲取不到它的node和resolve,所以會導致渲染失敗。這個時候可以通過:data顯示數據,當我們樹上有節點時,就可以正常觸發:load進行子節點的懶加載了。具體實現如下:
<template> <div class="org-tree"> <el-tree :data="orgList" :props="defaultProps" lazy :load="loadTree" :expand-on-click-node="false" @node-click="nodeClick"> </el-tree> </div> </template> <script> export default { name: 'Tree', props: { logicParams: { // 外部組件傳入的參數 type: Object } }, watch: { logicParams: { handler(newVal) { this.logicParams = newVal; if (this.circleI >0) { // 限制首次加載時只顯示loadTree加載的樹,而不是:data和loadTree加載的都有 this.resetNode(); } this.circleI++; }, immediate: true, deep: true } }, data() { return { defaultProps: { children: 'children', label: 'name', }, circleI: 0, orgList: [] } }, methods: { // 懶加載加載方法,首次加載樹的時候會被觸發 loadTree(node, resolve) { listByTree(this.logicParams).then(res => { // this.rootNode = node; // this.rootResolve = resolve; let rootMainResolve = resolve; let treedata = []; if(node.level == 0) { return resolve([{ name: res.data[0].name }]) } if (node.level == 1 ) { treedata.push(res.data) return resolve(...treedata) }; if (node.data.isParent && node.data.pId != '') { this.getChild(node.data, node.data.pId, rootMainResolve) } else { return resolve([]) // 防止不停轉圈 } }) }, getChild(data, type, resolve) { // 每個節點使用同一個接口獲取子節點,只是傳入的參數不同,將其抽出來 this.logicChildDataParam.id =data.id; this.logicChildDataParam.type = type+ ";;;"; listByTree(this.logicChildDataParam).then(res => { return resolve(res.data); }) }, // 重新渲染樹的根節點 resetNode() { listByTree(this.logicParams).then(res => { this.orgList = [res.data[0]] }) }, } } </script>
場景:在懶加載的樹上設置復選框,需要將之前添加好的懶加載選中的部分在表格的編輯中回顯出來。
思路:由于懶加載的數據是一級一級獲取的,所以可以利用default-expanded-keys和default-checked-keys屬性,將需要進行回顯的節點在渲染樹的時候就設置上去。(注意在使用這兩個屬性的時候)
<template> <div class="org-tree"> <el-tree ref="tree" :props="defaultProps" lazy :load="loadTree" :expand-on-click-node="false" show-checkbox @check-change="checkChange" :default-expanded-keys="defaultExpandKeys" :default-checked-keys="defaultCheckedKeys" node-key="id"> </el-tree> </div> </template> <script> export default { name: 'OrgTree', data() { return { defaultExpandKeys: [], defaultCheckedKeys: [] } }, methods: { // 當節點選中或取消選中的時候觸發,可接受三個參數(具體見官網,本項目只用觸發這個事件的時機) checkChange(data,state,childChecked) { let selectedAllList = []; let checkedList = []; // 選中所有的節點,包括半選節點(用作展開的節點) selectedAllList = this.$refs.tree.getCheckedNodes(false,true); // 選中所有全選節點,不包括半選(用作選中的節點) checkedList = this.$refs.tree.getCheckedNodes(); // 觸發父組件方法,將這兩個數組傳遞出去,并在父組件的添加點擊事件中調用添加方法,添加時需拿到這兩個節點數組用作數據的回顯 this.$emit('selectorg', selectedAllList, checkedList); }, loadTree(node, tree) { if (node.level == 0) { let che = []; let exp = []; // 此處的checkedList和selectedAllList是通過調用編輯接口獲取到的數據,為了方便理解寫做與checkChange中一樣,以下是偽代碼 checkedList.forEach(el => { // 遍歷選中的節點數組,拿到它們的id if (el.id) { che.push(el.id); } }) selectedAllList.forEach(el => { // 遍歷包括半選的節點數組,拿到它們的id(可以將半選節點都篩出來,將所有半選節點作為展開的節點,如果嫌麻煩可以將全選的接節點也展開,不過這樣可能會在樹的數據量過多的情況下出現延遲和卡頓,影響性能) if (el.id) { exp.push(el.id); } }) this.defaultCheckedKeys = che; // 將得到的回顯節點數組賦值給默認選中的數組 this.defaultExpandKeys = exp; // 將得到的展開節點數組賦值給默認展開的數組 } }, } } </script>
場景:在使用懶加載進行數據回顯時,當添加選中的數據里存在以下情況:一個父節點下的第一和第二個子節點同時被選中,回顯時得到的默認選中的節點數組里也只有這兩個節點的id,但是最終懶加載回顯的數據是這個父節點下的所有子節點全都被選中(獲取其他類似情況)。
分析:由于懶加載的樹是異步加載的,樹在判斷子節點是否選中的時候可能由于選中的子節點,而導致其父節點因為關聯而被計算判斷出選中。
解決一:如果不需要父節點的復選框,或者父節點沒有復選框,只有子節點有,或者不需要父子節點關聯的情況下,可以使用check-strictly屬性,斷開父子之間的連接:
<template> <div class="org-tree"> <el-tree ref="tree" :props="defaultProps" lazy :load="loadTree" :expand-on-click-node="false" show-checkbox @check-change="checkChange" :default-expanded-keys="defaultExpandKeys" :default-checked-keys="defaultCheckedKeys" node-key="id" :check-strictly="checkStrictly"> </el-tree> </div> </template> <script> export default { name: 'OrgTree', data() { return { checkStrictly: true, // 根據需要在可不同的位置定義 } } </script>
解決二:對選中節點的回顯不使用default-checked-keys,而是利用$nextTick和setCheckedKeys設置節點的選中,此方法必須設置node-key屬性:
<template> <div class="org-tree"> <el-tree ref="tree" :props="defaultProps" lazy :load="loadTree" :expand-on-click-node="false" show-checkbox @check-change="checkChange" :default-expanded-keys="defaultExpandKeys" :default-checked-keys="defaultCheckedKeys" node-key="id"> </el-tree> </div> </template> <script> export default { name: 'OrgTree', data() { return { defaultExpandKeys: [], defaultCheckedKeys: [] } }, methods: { // 當節點選中或取消選中的時候觸發,可接受三個參數(具體見官網,本項目只用觸發這個事件的時機) checkChange(data,state,childChecked) { let selectedAllList = []; let checkedList = []; // 選中所有的節點,包括半選節點(用作展開的節點) selectedAllList = this.$refs.tree.getCheckedNodes(false,true); // 選中所有全選節點,不包括半選(用作選中的節點) checkedList = this.$refs.tree.getCheckedNodes(); // 觸發父組件方法,將這兩個數組傳遞出去,并在父組件的添加點擊事件中調用添加方法,添加時需拿到這兩個節點數組用作數據的回顯 this.$emit('selectorg', selectedAllList, checkedList); }, loadTree(node, tree) { if (node.level == 0) { let che = []; let exp = []; // 此處的checkedList和selectedAllList是通過調用編輯接口獲取到的數據,為了方便理解寫做與checkChange中一樣,以下是偽代碼 selectedAllList.forEach(el => { // 遍歷包括半選的節點數組,拿到它們的id if (el.id) { exp.push(el.id); } }) this.defaultExpandKeys = exp; // 將得到的展開節點數組賦值給默認展開的數組 this.$nextTick(() => { // 利用$nextTick更新節點 checkedList.forEach(el => { // 遍歷選中的節點數組,拿到它們的id if (el.id) { che.push(el.id); } }) this.$refs.tree.setCheckedKeys(che); // 手動賦值節點 }) } }, } } </script>
注意:該方法因為在load方法中,所以每次觸發load的時候(每次首次下拉節點)都會重新獲取一邊數據,這會導致之前可能選中的節點又被回顯節點重置了。
這種情況如果在層級沒有超過2級時,可以通過設置一個計數器,讓這個$nextTick只執行一次,但是如果層級過多,下層還是會出現全選的情況。這個問題我暫時無法避免,所以綜合考慮下來還是采用每執行一次load就執行一次$nextTick,這樣可以保證更深的層級節點能正確顯示,對于回顯編輯來說,只要做到先下拉節點再選擇,就不會出錯了。
場景:現在需要去掉所有的葉子節點(沒有子節點的節點)的復選框,默認選中了父節點則其下所有子節點都 不做判斷。
思路:由于element的tree并未提供這個屬性或方法,需要我們自己手動去修改element內部代碼,然后再重新打包,將打好的包替換自己項目中element里的ilb文件夾:
將對應版本的element源碼下載下來,安裝依賴并查看項目是否啟動成功:
npm install npm run dev
運行成功后找到packages/tree/src/tree-node修改源碼:
<template> <div class="el-tree-node"> ... <!-- 找到復選框的位置,根據node.data中的某個字段判斷(我是根據isParent判斷)設置復選框的顯隱 --> <el-checkbox v-if="showCheckbox" v-model="node.checked" : :indeterminate="node.indeterminate" :disabled="!!node.disabled" @click.native.stop @change="handleCheckChange" > </el-checkbox> ... </div> </template>
源碼修改好之后,進行打包:
npm run dist
打包完成之后會得到新的lib文件夾,將其替換自己項目中的對應位置的lib文件夾即可。
注意:直接修改自己項目中的packages里的代碼是無效的,因為項目中所運行的是lib文件夾里的,packages只是方便查看內部源碼!
到此,關于“怎么使用vue el-tree實現懶加載數據和樹的過濾”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。