记一次关于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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于el-tree展开节点后是另一个el-tree的情况,你可以通过使用el-tree组件的自定义模板来实现。在展开节点时,你可以将子节点绑定到另一个el-tree组件的数据源中。 首先,确保你已经在项目中引入了el-tree组件。然后,在你的Vue组件中,可以这样定义el-tree组件: ```html <template> <div> <el-tree :data="treeData" :node-key="nodeKey" :props="defaultProps" @node-click="handleNodeClick"></el-tree> </div> </template> <script> export default { data() { return { treeData: [ { label: '节点1', children: [ { label: '子节点1', children: [ { label: '子节点1.1', }, { label: '子节点1.2', }, ], }, ], }, { label: '节点2', children: [ { label: '子节点2', children: [ { label: '子节点2.1', }, { label: '子节点2.2', }, ], }, ], }, ], nodeKey: 'label', defaultProps: { children: 'children', label: 'label', }, }; }, methods: { handleNodeClick(data) { // 在这里处理节点点击事件 // 获取点击的节点数据data,然后将其作为新的数据源赋值给另一个el-tree组件 this.treeData = data.children; }, }, }; </script> ``` 在上面的示例中,我们使用el-tree组件的data属性绑定了的数据源。当点击节点时,通过handleNodeClick方法获取到该节点的子节点数据,然后将其赋值给treeData,这样就实现了展开节点后显示另一个el-tree的效果。 注意,你可以根据实际需求修改数据结构和事件处理逻辑。这只是一个简单的示例,希望能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值