基於vue.js實現樹形表格的封裝

城池發表於2018-07-24

前言

由於公司產品(基於vue.js)需要,要實現一個樹形表格的功能,百度、google找了一通,並沒有發現很靠譜的,也不是很靈活。所以就用vue自己擼了一個,還望大家多多指教。

主要技術點:vue子元件的遞迴實現及相關樣式的實現

樹形表格實現

  • 效果圖(Demo)
    基於vue.js實現樹形表格的封裝
  • 主要程式碼

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沒有在頁面上有引入,但是也可以正常使用。這裡就是關健點,因為這個子元件是需要遞迴實現,所以,需要動態註冊到當前元件中。程式碼如下(由於程式碼太多,先貼圖說明吧,點選這裡可以看原始碼):

基於vue.js實現樹形表格的封裝

這裡子元件看起來是不是挺奇怪的,但是為了遞迴他本身,暫時也只想到這種辦法。如果有更好的辦法,歡迎留言指正。
那麼,樹表格的結構實現在哪裡呢??對,就是在子元件的模版(template)裡面,這裡就不貼程式碼了,可以移步到原始碼檢視。

  • 感謝

收到favourli的指正,現已將原有寫法更新,採用遞迴元件來實現,這樣頁面看起來就更清晰。

	components: {
			treeItem: () => import('./tree-item.vue')
	}
複製程式碼

補充一點:不要只看js部分,css部分才是這個樹表格的關健所在。當然裡面我採用了大量的計算屬性去判斷各種樣式的展示,還有一種方法,就是在initTreeData方法裡面去實現,這個方法就是處理或新增一些我們樹表格所使用的資訊。比如我現在在裡面實現的層級線的偏移量m.bLeft = level === 1 ? 34 : (level - 2) * 16 + 34 這個計算如果沒有看明白,可以留言。

最後,此篇乃我的開篇之作,如有問題,還請多多包含,多多指教!!!順便給我好久沒有更新的部落格打個廣告, 歡迎點選(一座城池

  • 原始碼地址github,歡迎star。

參考資源隔壁家的老黃

相關文章