Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作


Posted in Javascript onAugust 31, 2020

需求: vue-cli项目树形控件:一级节点为本地节点,默认展开一级节点,增删改后局部刷新数据。

Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作

增加节点,点击确定后局部刷新,渲染新数据。

Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作

源码

element组件样式

<el-tree 
        class="treeitems"
        :data="data"
        node-key="id"
        :props="defaultProps" 
        :load="loadNode"
        lazy
        :default-expanded-keys="[0]"
        @node-click="handleNodeClick"
        draggable
        :allow-drop="allowDrop"
        :allow-drag="allowDrag"
         @node-drop="handleDrop"
        ref="tree"
      >
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
          <i @click="() => append(node,data)" class="el-icon-plus"></i><!--增加分组-->
          <!-- 根节点不需要删除和重命名 -->
          <i v-if="data.id !== 0" @click="() => deletes(node,data)" class="el-icon-delete"></i><!--删除分组-->
          <i v-if="data.id !== 0" @click="() => rename(node,data)" class="el-icon-edit"></i><!--重命名分组-->
        </span>
      </span>
     </el-tree>

data数据

data() {
   return {
    filterText: '',
    data: [{
      id:0,
      label: '中国',
      
    }],
    children: [{
        id:1,
        label: '北京',
        children: [{
          id:11,
          label: '通州'
        }]
      },
      {  
        id:2,
        label: '上海',
        leaf: true,
      },
      {  
        id:3,
        label: '山西',
        children:[{
          id: 13,
          label: '太原'
        },{
          id: 14,
          label: '阳泉'
        }]
      },{
        id:4,
        label: '黑龙江',
        children: [{
          id:12,
          label: '哈尔滨'
        }]
      }],
    defaultProps: {
     children: 'children',
     label: 'label',
     isLeaf: 'leaf'
    }
   };

点击增加节点弹出弹窗

这里也用的是element的弹窗,直接在methods里写:

//点重命名事件
 append(node,data) {
      console.log(node,data,'增加')
      this.$prompt('节点名字', '增加节点', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        inputPattern: /^[\u4e00-\u9fa5]{0,}$/,//匹配全中文
        inputErrorMessage: '请输入中文'//不符合正则匹配的提示语句
        }).then(({ value }) => {
          //可以在这里发请求,http是我模拟的一个虚假的封装好的axios请求,()可写请求参数
          http().then((data)=>{
            this.$message({
              type: 'success',
              message: '修改成功'
            }); 
            //请求成功需局部刷新该节点,调用方法,把节点信息node传入
            this.partialRefresh(node)
          })
          //请求失败
          .catch(()=>{
            this.$message({
              type: 'info',
              message: '修改失败'
            }); 
          })
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '取消修改'
          });    
      });
    },
    //实现局部刷新,在点击弹窗处调用的
    partialRefreshpartialRefresh(node){
      //设置loaded为false;模拟一次节点展开事件,加载重命名后的新数据;
      node.loaded = false;
      node.expand(); 
      //新建子节点是刷新一次本节点的展开请求,而重命名和删除则需要刷新父级节点的的展开事件,
      //可以设置node.parent.loaded = false;node.parent.expand();
    },

懒加载

Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作

该处可直接设置有无节点,如果后端返回有无节点的表示就可用,若无可舍弃。(data中写,我在本地模拟数据上海字段中加了leaf: true,上海节点就默认没有节点了)

//懒加载
    loadNode(node, resolve){
      if (node.level === 0) {
        //本地的数据,一个承载中国字样的数组;
        return resolve(this.data);
      }
      else if(node.level === 1){
        //现在为模拟数据;
        //有真实数据,在resolve中放置请求回来的数据即可。
        //else同样也是。我这里是区分了两种请求方式。
        return resolve(this.children)
      }
      else{
        return resolve([])
      }
    },

拖拽节点

//拖拽==>拖拽时判定目标节点能否被放置
    allowDrop(draggingNode, dropNode, type){
      //参数:被拖拽节点,要拖拽到的位置
      //因为根目录是我本地写死的,不能有同级,所以我设置凡是拖拽到的level===1都存放到根节点的下面;
      if(dropNode.level===1){
        return type == 'inner';
      }
      else {
        return true;
      }
    },
    //拖拽==>判断节点能否被拖拽
    allowDrag(draggingNode){
     //第一级节点不允许拖拽
      return draggingNode.level !== 1;
    },

需求改了,同级节点拖拽,拖拽完成后将排序结果返回后端:

//拖拽==>拖拽时判定目标节点能否被放置
    //后更改为只能同级拖拽
    allowDrop(draggingNode, dropNode, type) {
      if (draggingNode.level === dropNode.level) {
        if (draggingNode.data.parentId === dropNode.data.parentId) {
          return type === 'prev' || type === 'next'
        }
      } else {
        // 不同级不允许拖拽
        return false
      }
    },
    //拖拽==>判断节点能否被拖拽
    allowDrag(draggingNode) {
      return draggingNode.level !== 1;
    },
    //拖拽成功完成时触发的事件,在这里可以将节点拖拽后的顺序返给后端
    handleDrop(node,data,type,event){
      let arr=[];
      //data为拖拽后节点信息,找到它的父级,在从父级找子集
      let child = data.parent.childNodes;
      for(var key in child){
        arr.push({id:child[key].data.id})
      }
      //转为JSON字符串发请求带走信息
      idSort(JSON.stringify(arr))
    }

补充知识:vue+element tree ----增加修改删除上下移动

<template>
 <div>
  <div class="exam_structure">
   <el-input
    placeholder="输入关键字进行过滤"
    v-model="filterText">
   </el-input>
 
 
   <el-button type="primary" size="small" class="add_new_question" @click="add_new_question"><i></i>添加父节点</el-button>
 
  </div>
 
  <div class="question_info_lists">
 
   <el-tree ref="tree" :key="tree_key" :data="treeData" node-key="id" :render-content="renderContent"
        :expand-on-click-node="false" :default-expanded-keys="defaultExpand" show-checkbox
        :filter-node-method="filterNode"></el-tree> 
 
   <el-row class="add_question" v-show="add_question_flag">
 
    <el-col :span="12">
 
     <el-input v-model="new_question_name" placeholder="请输入大题名称"></el-input>
 
    </el-col>
 
    <el-col :span="12">
 
     <el-button size="mini" class="btn_sure" @click.stop="add_question_sure">确定</el-button>
 
     <el-button size="mini" class="btn_cancel" @click.stop="add_question_cancel">取消</el-button>
 
    </el-col>
 
   </el-row>
 
  </div>
 </div>
</template>
 
<script>
 export default {
  name: "tree1",
 
  watch: {
   filterText(val) {
    this.$refs.tree.filter(val);
   }
  }, 
 
  methods: {
   filterNode(value, data) {
    if (!value) return true;
    return data.label.indexOf(value) !== -1;
   },
// 添加新大题
 
   add_new_question() { 
    this.add_question_flag = true 
   },
 
   add_question_sure() {  //确定
 
    const nodeObj = {id: '', label: this.new_question_name, isEdit: false, children: []}
    this.treeData.push(nodeObj)
    this.add_question_flag = false
 
   },
 
   add_question_cancel() {  //取消 
    this.add_question_flag = false 
    this.new_question_name = '' 
   },
 
   //   增加
   append(store, node, data) {
    var maxid = '20'
    //新增数据
    const nodeapp = {id: ++maxid, label: '增加节点', isEdit: false, children: []}
    data.children.push(nodeapp)
    if (!node.expanded) {
     node.expanded = true
    }
    const parent = node.parent
    const children = parent.data
    const cIndex = children.findIndex(d => d.id === data.id)
    const tempChildrenNodex2 = children[cIndex] //拿到被添加的上一级
    console.log(tempChildrenNodex2.children[cIndex - 1])
   },
 
// 修改
 
   nodeEdit(ev, store, data) { 
    data.isEdit = true 
    this.$nextTick(() => { 
     const $input = ev.target.parentNode.parentNode.querySelector('input') || ev.target.parentElement.parentElement.querySelector('input') 
 
     !$input ? '' : $input.focus() 
    }) 
   },
 
   edit_sure(ev, data) { 
    const $input = ev.target.parentNode.parentNode.querySelector('input') || ev.target.parentElement.parentElement.querySelector('input') 
 
    if (!$input) { 
     return false 
    } else { 
     data.label = $input.value 
     data.isEdit = false 
    } 
   },
 
// 节点删除 
   nodeDelete(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) 
   },
 
// 节点上移
 
   nodeUp(node, data) { 
    const parent = node.parent 
    const children = parent.data.children || parent.data 
    const cIndex = children.findIndex(d => d.id === data.id) 
    if (parent.level === 0 && cIndex === 0) { 
     return 
    } else if (parent.level !== 0 && cIndex === 0) { //不同父节点中移动
     alert('不同父节点中移动')
 
     // const parent2 = parent.parent 
     // const children2 = parent2.data.children || parent2.data 
     // const pIndex2 = parseInt(children2.findIndex(p => p.id === parent.data.id), 10) - 1 
 
     // if (pIndex2 < 0) return 
     // children2[pIndex2].children.push(data) 
     // children.splice(cIndex, 1)
 
     // this.defaultExpand[0] = children2[pIndex2].id
 
    } else if ((parent.level === 0 && cIndex !== 0) || (parent.level !== 0 && cIndex !== 0)) {
 
     const tempChildrenNodex1 = children[cIndex - 1] 
     const tempChildrenNodex2 = children[cIndex] 
     this.$set(children, cIndex - 1, tempChildrenNodex2) 
     this.$set(children, cIndex, tempChildrenNodex1) 
     this.defaultExpand[0] = data.id 
    }
 
    this.tree_key++ 
   },
 
// 节点下移
 
   nodeDown(store, node, data) { 
    const parent = node.parent
    const children = parent.data.children || parent.data
    const cIndex = children.findIndex(d => d.id === data.id)
    const cLength = children.length - 1 // 最边上的节点
    const allLevel = store.data.length - 1 // 树的深度 
 
    if (parent.level === allLevel && cIndex === cLength) { // 最最末的节点
 
     return
 
    } else if (parent.level !== allLevel && cIndex === cLength) { //父节点不同
     alert('不能移动')
     // const parent2 = parent.parent
 
     // const children2 = parent2.data.children || parent2.data
 
     // const pIndex2 = parseInt((children2.findIndex(p => p.id === parent.data.id)), 10) 
 
     // if (pIndex2 === allLevel) return
 
     // children2[pIndex2 + 1].children.push(data)
 
     // children.splice(cIndex, 1)
 
     // this.defaultExpand[0] = children2[pIndex2 + 1].id
 
    } else if ((parent.level === allLevel && cIndex !== cLength) || (parent.level !== allLevel && cIndex !== cLength)) { // 父节点相同
 
     const tempChildrenNodex1 = children[cIndex + 1] 
     const tempChildrenNodex2 = children[cIndex] 
 
     this.$set(children, cIndex + 1, tempChildrenNodex2) 
     this.$set(children, cIndex, tempChildrenNodex1) 
     this.defaultExpand[0] = data.id 
    } 
    this.tree_key++ 
   },
 
   showOrEdit(data) { 
    if (data.isEdit) { 
     return <input type="text" value={data.label} on-blur={ev => this.edit_sure(ev, data)}/> 
    } else { 
     return <span className="node_labe">{data.label}</span> 
    } 
   },
 
// 结构树操作group node, 
   renderContent(h, {node, data, store}) { 
    return ( 
     <span> 
<span class="el-icon-document"> 
{this.showOrEdit(data)} 
</span> 
<div class="tree_node_op" style=" float: right"> 
<i class="el-icon-edit" on-click={(ev) => this.nodeEdit(ev, store, data)}></i> 
<i class="el-icon-delete" on-click={() => this.nodeDelete(node, data)}></i> 
<i class="el-icon-upload2" on-click={() => this.nodeUp(node, data)}></i> 
<i class="el-icon-download" on-click={() => this.nodeDown(store, node, data)}></i>
<i class="el-icon-plus" on-click={() => this.append(store, node, data)}></i>
 
</div> 
</span>) 
   } 
  }
  , data() { 
   return {
    filterText: '',
    treeData: [{
 
     id: 1, 
     label: '一级 1', 
     isEdit: false, 
     children: [{ 
      id: 4, 
      label: '二级 1-1', 
      isEdit: false, 
      children: [{id: 9, label: '三级 1-1-1', isEdit: false, children: []}, {
       id: 10,
       label: '三级 1-1-2',
       isEdit: false,
       children: []
      }, {
       id: 11,
       label: '三级 1-1-3',
       isEdit: false,
    children: []
      }] 
     },
 
      { 
       id: 12, 
       label: '二级 1-2', 
       isEdit: false, 
       children: [] 
      },
 
      { 
       id: 13, 
       label: '二级 1-3', 
       isEdit: false, 
       children: [] 
      }] 
    },
 
     { 
      id: 2, 
      label: '一级 2', 
      isEdit: false,
       children: [{id: 5, label: '二级 2-1', isEdit: false, children: []}, {
       id: 6,
       label: '二级 2-2',
       isEdit: false,
       children: []
      }] 
     },
 
     { 
      id: 3, 
      label: '一级 3', 
      isEdit: false, 
      children: [
       {id: 7, label: '二级 3-1', isEdit: false, children: []},
       {
       id: 8,
       label: '二级 3-2',
       isEdit: false,
       children: []
      }] 
     }],
 
    add_question_flag: false, 
    new_question_name: '', 
    tree_key: 0, 
    defaultExpand: [] 
   } 
  }, 
 }
</script> 
<style scoped> 
</style>

Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作

以上这篇Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 类的定义和引用 JavaScript高级培训 自定义对象
Apr 27 Javascript
纯JS实现动态时间显示代码
Feb 08 Javascript
JavaScript事件委托的技术原理探讨示例
Apr 17 Javascript
深入理解JavaScript系列(33):设计模式之策略模式详解
Mar 03 Javascript
Javascript对象Clone实例分析
Jun 09 Javascript
jQuery实现鼠标经过弹出提示信息的地图热点效果
Aug 07 Javascript
分享javascript、jquery实用代码段
Oct 20 Javascript
mongoose设置unique不生效问题的解决及如何移除unique的限制
Nov 07 Javascript
用最少的JS代码写出贪吃蛇游戏
Jan 12 Javascript
vuejs选中当前样式active的实例
Aug 22 Javascript
vue中使用codemirror的实例详解
Nov 01 Javascript
使用Vue.js中的过滤器实现幂方求值的方法
Aug 27 Javascript
JS遍历树层级关系实现原理解析
Aug 31 #Javascript
Element-ui el-tree新增和删除节点后如何刷新tree的实例
Aug 31 #Javascript
Vue循环中多个input绑定指定v-model实例
Aug 31 #Javascript
浅析 Vue 3.0 的组装式 API(一)
Aug 31 #Javascript
vue中v-model对select的绑定操作
Aug 31 #Javascript
Vue v-for中的 input 或 select的值发生改变时触发事件操作
Aug 31 #Javascript
vue绑定数字类型 value为数字的实例
Aug 31 #Javascript
You might like
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
2018/06/13 PHP
对google个性主页的拖拽效果的js的完整注释[转]
2007/04/10 Javascript
浅谈jQuery异步对象(XMLHttpRequest)
2014/11/17 Javascript
jquery利用命名空间移除绑定事件的方法
2015/03/11 Javascript
AngularJs 弹出模态框(model)
2016/04/07 Javascript
JSON 必知必会 观后记
2016/10/27 Javascript
微信JS-SDK自定义分享功能实例详解【分享给朋友/分享到朋友圈】
2016/11/25 Javascript
less简单入门(CSS 预处理语言)
2017/03/08 Javascript
vue 如何添加全局函数或全局变量以及单页面的title设置总结
2017/06/01 Javascript
JavaScript中作用域链的概念及用途讲解
2020/08/06 Javascript
[04:26]2014DOTA2国际邀请赛-Newbee顺利进入胜者组决赛 独家专访战神7
2014/07/19 DOTA
[44:15]国士无双DOTA2 6.82版本详解(上)
2014/09/28 DOTA
[01:54]TI珍贵瞬间系列(五):压力
2020/08/29 DOTA
布同 统计英文单词的个数的python代码
2011/03/13 Python
python编程实现归并排序
2017/04/14 Python
Python Json模块中dumps、loads、dump、load函数介绍
2018/05/15 Python
Python中pip更新和三方插件安装说明
2018/07/08 Python
TensorFlow利用saver保存和提取参数的实例
2018/07/26 Python
Python爬虫使用浏览器cookies:browsercookie过程解析
2019/10/22 Python
Python MySQL 日期时间格式化作为参数的操作
2020/03/02 Python
解决Jupyter Notebook使用parser.parse_args出现错误问题
2020/04/20 Python
python 实现倒计时功能(gui界面)
2020/11/11 Python
HTML5中如何显示视频呢 HTML5视频播放demo
2013/06/08 HTML / CSS
洛佩桑酒店官方网站:Lopesan Hotels
2019/04/15 全球购物
新西兰最大、占有率最高的综合性药房:PharmacyDirect药房中文网
2020/11/03 全球购物
J2SDK1.5与J2SDK5.0有什么区别
2012/09/19 面试题
企业行政文员岗位职责
2013/12/03 职场文书
大型活动组织方案
2014/05/10 职场文书
应届大专生求职信
2014/06/26 职场文书
幼儿园清明节活动总结
2014/07/04 职场文书
出纳试用期自我鉴定范文
2014/09/16 职场文书
运动会报道稿300字
2014/10/02 职场文书
大学生联谊活动策划书(光棍节)
2014/10/10 职场文书
再婚婚前财产协议书范本
2014/10/19 职场文书
童年读书笔记
2015/06/26 职场文书
学校标语口号大全
2015/12/26 职场文书