- 在實際項目開發中,當 tree 的某個節點大於 2000 個時,dom 渲染起來就非常慢,整個頁面就會卡了起來.
- 基於 vue elementUI 來開發,用到了 InfiniteScroll 無限滾動 Tree 樹形控件
- 來個 demo,具體看下 tree 子節點過多時的卡頓吧。
- 優化思路就是 前端剛開始只加載 10 個子節點,當滾動到底部時,再增加 10 個。
<div id="app">
<div
class="tree-box1"
:infinite-scroll-immediate="false"
v-infinite-scroll="load"
>
<el-tree
:data="curList"
v-loading="loading"
default-expand-all
:props="defaultProps"
@node-click="handleNodeClick"
></el-tree>
</div>
</div>
<style>
.tree-box1 {
height: 200px;
overflow: auto;
}
</style>
<script>
var Main = {
data() {
return {
loading: false,
curtreePageSize: 10,
allList: [],
curList: [],
defaultProps: {
children: 'children',
label: 'label',
},
}
},
methods: {
//滾動軸滾動最底部觸發,tree的數組動態增加
load() {
if (this.allList.length) {
console.log('滾動')
this.curtreePageSize += 10
this.curList = this.sliceTree(this.allList, this.curtreePageSize)
}
},
handleNodeClick(data) {
console.log(data)
},
//tree數組的截取,默認截取10個,可以動態配置
sliceTree(data, len = 10) {
return [
{
label: '一級 1',
children: data.slice(0, len),
},
]
},
// 這是模擬跟后端的請求;用setTimeout模擬
impersonationRequest() {
this.loading = true
let arr = []
for (let i = 1; i < 4000; i++) {
arr.push({ label: `二級 1-${i}` })
}
setTimeout(() => {
this.allList = arr
this.curList = this.sliceTree(this.allList)
this.loading = false
}, 1000)
},
},
mounted() {
this.impersonationRequest()
},
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
</script>
- 好了基本完結,假如你不用el-tree自帶的關鍵字過濾樹節點的話。
又或者后端大佬願意幫你寫個接口,返回過濾后的tree給你;
不然的話,你就自己來實現了。el-tree本身的過濾是沒有問題的,但是你用了懶加載,例如只加載了10個,它只會在你10個里面來進行搜索;你就需要自己寫個算法來實現;
核心代碼如下
/**
* data 為 tree數據
* name 為 篩選關鍵詞
**/
const filterTree = (data, name) => {
// 當name數據為空時,返回默認的10個數據dom
if (!name) {
this.curList = this.sliceTree(this.allList)
return
}
const PrimaryNode = [...data] //數組
// 遞歸的方法,來判斷
function traverse (node) {
node.forEach(v => {
//假如當前節點的屬性滿足 關鍵詞,則將當前節點的visible屬性設置為tree
v.visible = v.label.includes(name)
//如果純在子節點,就遞歸調用本函數
if (v.children) {
traverse(v.children)
}
/* 當前節點visible為false, 且有子節點的再判斷一次
假如子節點存在visible為true,則父節點的visible也設置成tree
這個涉及到遞歸的執行順序問題,我們假如搜索的孫子節點三級,
const tree = [{
label:'一級',
children:[{
label: '二級',
children:[{
label: '三級',
}]
}]
}]
下面代碼執行順序是從最深處開始執行,然后漸漸到外層的,所以不會有問題;
*/
if (!v.visible && v.children) {
v.visible = v.children.some(child => child.visible)
}
})
}
//第二個函數的作用,就是過濾掉visible為false的選項。比較容易理解
function filterName (node) {
const newNode = node.filter(v => v.visible)
newNode.forEach(v => {
if (v.children) {
v.children = filterName(v.children)
}
})
return newNode
}
traverse(PrimaryNode)
const filterNode = filterName(PrimaryNode).slice(0,100)
if(filterNode.length) {
this.curList = [{
label: '一級 1',
children: filterNode
}]
}else {
this.curList = []
}
},