前言
由於公司產品(基於vue.js)需要,要實現一個樹形表格的功能,百度、google找了一通,並沒有發現很靠譜的,也不是很靈活。所以就用vue自己擼了一個,還望大家多多指教。
主要技術點:vue子元件的遞迴實現及相關樣式的實現
樹形表格實現
- 效果圖(Demo)
- 主要程式碼
index.vue頁面實現業務邏輯程式碼,比如樹表格上面的一些操作按鈕的實現及資料獲取。
<template>
<div class="contains">
<h1>樹表格實現</h1>
<tree-table ref="recTree"
:list.sync="treeDataSource"
@actionFunc="actionFunc"
@deleteFunc="deleteFunc"
@orderByFunc="orderByFunc"></tree-table>
</div>
</template>
<script>
import treeTable from '@/components/tree-table.vue'
export default {
data() {
return {
list: [], // 請求原始資料
treeDataSource: [] // 組合成樹表格接收的資料
}
},
components: {
treeTable
},
methods: {
orderByFunc(val) {
alert('排序')
alert(val)
},
actionFunc(m) {
alert('編輯')
},
deleteFunc(m) {
alert('刪除')
}
}
}
</script>
複製程式碼
原始資料`list`:是不包含子資料的資料結構,即沒有層級結構,例如:
[{id:111,parentId:0,name:'父及'},{id:111,parentId:111,name:'子級'}...],通過parentId來獲取對應父子層級結構
`treeDataSource`:是樹表格需要的資料結構,例如:
[{id:0,name:'父及',children:[{id:10,name:'子級',children:[]}]},...]
複製程式碼
如果後臺返回給你的是原始資料格式,就可以用下面方法封裝成樹表格可以使用的資料結構:
getTreeData() {
// 取父節點
let parentArr = this.list.filter(l => l.parentId === 0)
this.treeDataSource = this.getTreeData(this.list, parentArr)
},
// 這裡處理沒有children結構的資料
getTreeData(list, dataArr) {
dataArr.map((pNode, i) => {
let childObj = []
list.map((cNode, j) => {
if (pNode.Id === cNode.parentId) {
childObj.push(cNode)
}
})
pNode.children = childObj
if (childObj.length > 0) {
this.getTreeData(list, childObj)
}
})
return dataArr
}
複製程式碼
tree-table.vue頁面。此頁面是實現樹表格的關健頁面。主要程式碼如下:
<template>
<div class="tree-table">
<div class="tree-head">
<table>
<tr>
<td class="td1">職位名稱</td>
<td class="td2">負責人</td>
<td class="td3" @click="isDesc=!isDesc">
建立時間
<div class="arrow">
<span class="up-arrow" :class="{'sort':isDesc}"></span>
<span class="down-arrow" :class="{'sort':!isDesc}"></span>
</div>
</td>
<td class="td4">工作經驗</td>
<td class="td5">釋出時間</td>
<td class="td6">操作</td>
</tr>
</table>
</div>
<div id="scrollWrap" class="tree-wrap">
<div class="tree-body">
<table v-if='treeDataSource.length>0'>
<tbody>
<tr>
<td>
<tree-item
v-for="(model,i) in treeDataSource"
:key="'root_node_'+i"
:root="0"
:num="i"
@actionFunc="actionFunc"
@deleteFunc="deleteFunc"
:nodes="treeDataSource.length"
:trees.sync="treeDataSource"
:model.sync="model">
</tree-item>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
複製程式碼
首先這裡的子元件tree-item
沒有在頁面上有引入,但是也可以正常使用。這裡就是關健點,因為這個子元件是需要遞迴實現,所以,需要動態註冊到當前元件中。程式碼如下(由於程式碼太多,先貼圖說明吧,點選這裡可以看原始碼):
這裡子元件看起來是不是挺奇怪的,但是為了遞迴他本身,暫時也只想到這種辦法。如果有更好的辦法,歡迎留言指正。
那麼,樹表格的結構實現在哪裡呢??對,就是在子元件的模版(template
)裡面,這裡就不貼程式碼了,可以移步到原始碼檢視。
- 感謝
components: {
treeItem: () => import('./tree-item.vue')
}
複製程式碼
補充一點:不要只看js部分,css部分才是這個樹表格的關健所在。當然裡面我採用了大量的計算屬性去判斷各種樣式的展示,還有一種方法,就是在
initTreeData
方法裡面去實現,這個方法就是處理或新增一些我們樹表格所使用的資訊。比如我現在在裡面實現的層級線的偏移量m.bLeft = level === 1 ? 34 : (level - 2) * 16 + 34
這個計算如果沒有看明白,可以留言。
最後,此篇乃我的開篇之作,如有問題,還請多多包含,多多指教!!!順便給我好久沒有更新的部落格打個廣告, 歡迎點選(一座城池)
- 原始碼地址github,歡迎star。
參考資源隔壁家的老黃