記一次關於el-tree文件樹的實操使用經歷

使用過程描述:文件目錄樹的操作要求是,樹的結構數據不能一次性吐出,點擊樹的節點,加載該節點下的數據,除了數據加載的情況外,還有相關子節點的新建。當時沒有看elementUI關於el-tree組件的詳細文檔,就是感覺文件數在數據子節點的遞歸上會有麻煩;所以試過幾個方法,嘗試過自己寫組件,利用遞歸的方法一次性將文件數加載出來,最後勉強能夠加載,但是新增子節點這塊又遇到麻煩,就是還要根據遞歸將新增的子節點加載到選中的節點下,還是用遞歸,整個過程寫下來很痛苦,使用的體驗也不是很完美。最後又倒騰到el-tree上,回到官網老老實實滴看了各種函數使用說明。歸結起來找到el-tree的擴展方法:新增子節點和刪除子節點。

<el-tree
      :data="data"
      show-checkbox
      node-key="id"
      ref="tree"
      default-expand-all
      :expand-on-click-node="false">
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
          <el-button
            type="text"
            size="mini"
            @click="() => append(data)">
            Append
          </el-button>
          <el-button
            type="text"
            size="mini"
            @click="() => remove(node, data)">
            Delete
          </el-button>
        </span>
      </span>
    </el-tree>



append(data) {
    const newChild = { id: id++, label: 'testtest', children: [] };
    if (!data.children) {
      this.$set(data, 'children', []);
    }
    data.children.push(newChild);
},

remove(node, data) {
    const parent = node.parent;
    const children = parent.data.children || parent.data;
    const index = children.findIndex(d => d.id === data.id);
    children.splice(index, 1);
}

通過嘗試,的確可以滿足大部分的使用需求,但是依然存在問題。新增節點靜態數據插入到目標節點上是沒問題,但是實際情況是需要先查詢當前目標節點的children的數據,然後將新增的data數據push到children,最後將children利用$set方法改變目標節點。實際操作中邏輯沒有問題,但就是不成功,通過控制檯打印出來的結果也是新增了一條的數據children,可是文件樹卻不能更新。使用了官網提供的updateKeyChildren(通過 keys 設置節點子元素,使用此方法必須設置 node-key 屬性)也沒有用。後來通過控制檯打印觀察,發現每次操作更新節點數據之前children數據已經被更新,但是感覺就是有一個點沒有抓住,網上查找了很多資料,找到一個關於date數據深拷貝的說法,感覺很有道理,就試了試,沒想到竟然真的成功了。一個問題困擾了自己好多天,終於被解決的感覺真是太美妙了。

完整代碼如下,供下次參考。

<el-tree ref="tree" :data="dataTree"
    :props="defaultProps"
    node-key="id"
    :default-expand-all="true"    // 目錄樹默認是否全部展開
    :highlight-current="true"     // 選中節點是否高亮(加背景色區分)
      :expand-on-click-node="false"
      @node-click="handleNodeClick">
    <span class="custom-tree-node" slot-scope="{ node, data }">
      <span v-if="!data.isedit">
        <i class="el-icon-folder"></i>
        {{ node.label }}</span>
      <span v-else>
        <el-input v-model="data.dirName" size="mini" @keyup.enter.native="saveDir(data)">
          <!-- <template slot="append" style="padding: 0 10px;">
            <i class="el-icon-check" @click.stop="saveDir(data)"></i></template> -->
        </el-input>
      </span>
      <span style="font-size:20px;">
        <el-button type="text" size="mini" @click.stop="() => append(data,node)">
          <i class="el-icon-plus"></i>
        </el-button>
        <el-button type="text" size="mini" v-if="node.level !== 1"
          @click="() => editDir(node,data)">
          <i class="el-icon-edit"></i>
        </el-button>
        <el-button type="text" size="mini" v-if="node.level !== 1" @click="() => remove(node, data)">
          <i class="el-icon-delete"></i>
        </el-button>
      </span>
    </span>
</el-tree>
// JS部分
// 這步的操作是解決問題的關鍵  
// let dataObj = JSON.parse(JSON.stringify(data)) // 深度拷貝


async append (data,node) {
  // 這步的操作是解決問題的關鍵  
  let dataObj = JSON.parse(JSON.stringify(data)) // 深度拷貝
  // 先查詢當前文件夾是否有子目錄
  if (dataObj.children.length === 0) {
    let result  = await this.$axios.getMyDirectoryList({directorypath: dataObj.dirPath})
    let res = this.$formatdata(result)
    if (res.code === 10000 && res.data.length > 0) {
      res.data.forEach(item=>{
        item.isedit=false;
        item.isUpdate=false;
        item.children=[]
        dataObj.children.push(item)
      })
      this.setNewFolder(dataObj, node)
    } else {
      this.setNewFolder(dataObj, node)
    }
  } else {
    this.setNewFolder(dataObj, node)
  }
  
},
setNewFolder (data,node) {
  let dataChild = data.children
  let dirName = '新建文件夾'
  if (dataChild) {
    let count=1
    dataChild.forEach(item => {
      if (item.dirName.indexOf('新建文件夾')>-1) {
        count++
      }
    })
    dirName += count
  }
  // 新增節點對象
  const newChild = {
    id: data.dirPath+'/'+dirName,
    dirName,
    dirPath:data.dirPath+'/'+dirName,
    parentId: data.dirPath,
    isedit: true,
    isUpdate: false,
    children: []
  }
  if (!data.children) {
    this.$set(data, 'children', []);
  }
  dataChild.push(newChild);
  this.$nextTick(() => {
  //   this.$set(data, 'children', data.children);
    this.$refs['tree'].updateKeyChildren(data.id,dataChild)
  })
},

 

this.$refs['tree'].updateKeyChildren(data.id,dataChild)
// 這個方法可以脫離函數對象流操作文件樹,只要知道目標對象,以及新增之後的對象數組即可使用此方法更新el-tree對象
// 使用注意點:通過 keys 設置節點子元素,使用此方法必須設置 node-key 屬性

記錄下這段文字希望爲遇到同樣問題的童鞋們提供點參考,記得深拷貝試試,哈哈!!!

 

el-tree 官網擴展:

props

參數

說明

類型

可選值

默認值

label

指定節點標籤爲節點對象的某個屬性值

string, function(data, node)

children

指定子樹爲節點對象的某個屬性值

string

disabled

指定節點選擇框是否禁用爲節點對象的某個屬性值

boolean, function(data, node)

isLeaf

指定節點是否爲葉子節點,僅在指定了 lazy 屬性的情況下生效

boolean, function(data, node)

 

//props的使用舉例
<template>
<el-tree :data="data" :props="defaultProps"></el-tree>
</template>
<script>
    export default{
        data () {
            return {
                data: [
                {title:'一級目錄', list: [
                    {
                        title: '二級目錄',
                        list: [...]
                    }
                    ]}
                ],
                defaultProps:{
                    label: 'title',    // label代替data裏面的title顯示在目錄樹上
                    children: 'list'   // children代替data裏面的list顯示子節點目錄樹
                }
            }
        }
    }
</script>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章