VUE饿了么树形控件添加增删改功能的示例代码


Posted in Javascript onOctober 17, 2017

本文介绍了VUE饿了么树形控件添加增删改功能的示例代码,分享给大家,具体如下:

element-ui树形控件:地址

在原文档中有个案例是有新增和删除功能,但是后来发现其修改的数据并不能直接影响到树形数据,所以采用了 render-content 的API重新写了个组件。

写个开发的步骤,所以文章比较长emmm

大致效果如图:

VUE饿了么树形控件添加增删改功能的示例代码

1.省市API

在网上复制了个省市的list,有两个属性是新增的

  • isEdit :控制编辑状态
  • maxexpandId :为现下id的最大值
export default{

  maxexpandId: 95,
  treelist: [{ 
    id: 1, 
    name: "北京市", 
    ProSort: 1, 
    remark: "直辖市",
    pid: '',
    isEdit: false,
    children: [{
      id: 35,
      name: "朝阳区",
      pid: 1,
      remark: '',
      isEdit: false,
      children: []
    }]
  }{...}]
}

2.el-tree Component基本

咱们一步步来,先写个饿了么的组件

<template>
  <el-tree ref="expandMenuList" class="expand-tree"
    v-if="isLoadingTree"
    :data="setTree"
    node-key="id"
    highlight-current
    :props="defaultProps"
    :expand-on-click-node="false"
    :render-content="renderContent"
    :default-expanded-keys="defaultExpandKeys"></el-tree>
</template>
<!--
* highlight-current :为了点击时节点高亮
* expand-on-click-node : 只能箭头控制树形的展开收缩
* render-content : 节点渲染方式
* default-expanded-keys :默认展开节点
-->

同时引入API和节点渲染的组件

import TreeRender from '@/components/tree_render'
import api from '@/resource/api'

然后搭建好基础

data(){
 return{
  maxexpandId: api.maxexpandId,//新增节点开始id
  non_maxexpandId: api.maxexpandId,//新增节点开始id(不更改)
  isLoadingTree: false,//是否加载节点树
  setTree: api.treelist,//节点树数据
  defaultProps: {
   children: 'children',
   label: 'name'
  },
  defaultExpandKeys: [],//默认展开节点列表
 }
},

添加个渲染的method

methods: {
  renderContent(h,{node,data,store}){
   let that = this;//指向vue
   return h(TreeRender,{
    props: {
     DATA: data,//节点数据
     NODE: node,//节点内容
     STORE: store,//完整树形内容
    },
    on: {//绑定方法
     nodeAdd: ((s,d,n) => that.handleAdd(s,d,n)),
     nodeEdit: ((s,d,n) => that.handleEdit(s,d,n)),
     nodeDel: ((s,d,n) => that.handleDelete(s,d,n))
    }
   });
  },
  handleAdd(s,d,n){//增加节点
   console.log(s,d,n)
  },
  handleEdit(s,d,n){//编辑节点
   console.log(s,d,n)
  },
  handleDelete(s,d,n){//删除节点
   console.log(s,d,n)
  }
}

3.tree_render Component基本

渲染组件:

<template>
  <span class="tree-expand">
    <span class="tree-label">
      <span>{{DATA.name}}</span>
    </span>
    <span class="tree-btn">
      <i class="el-icon-plus" @click.stop="nodeAdd(STORE,DATA,NODE)"></i>
      <i class="el-icon-edit" @click.stop="nodeEdit(STORE,DATA,NODE)"></i>
      <i class="el-icon-delete" @click.stop="nodeDel(STORE,DATA,NODE)"></i>
    </span>
  </span>
</template>

添加好几个按钮(element-ui自带icon:地址)对应的方法:

export default{
  props: ['NODE', 'DATA', 'STORE'],
  methods: {
   nodeAdd(s,d,n){//新增
    this.$emit('nodeAdd',s,d,n)
   },
   nodeEdit(s,d,n){//编辑
    this.$emit('nodeEdit',s,d,n)
   },
   nodeDel(s,d,n){//删除
    this.$emit('nodeDel',s,d,n)
   }
  }
}

4.改

我们用isEdit来切换input和span的显示状态,首先加个input:

<!-- tree_render component -->
<template>
  <span class="tree-expand">
    <span class="tree-label" v-if="DATA.isEdit">
      <el-input class="edit" size="mini"
      :ref="'treeInput'+DATA.id"
      v-model="DATA.name"></el-input>
    </span>
    <template v-else>
      <span class="tree-label">
        <span>{{DATA.name}}</span>
      </span>
      <span class="tree-btn" v-show="!DATA.isEdit">
        <i class="el-icon-plus" @click.stop="nodeAdd(STORE,DATA,NODE)"></i>
        <i class="el-icon-edit" @click.stop="nodeEdit(STORE,DATA,NODE)"></i>
        <i class="el-icon-delete" @click.stop="nodeDel(STORE,DATA,NODE)"></i>
      </span>
    </template>
  </span>
</template>

编辑的时候按钮同时消失,那么什么时候编辑完成呢?

  • 编辑完按enter键=》监听input的enter输入
  • 点击其他节点=》input失焦-blur=》编辑时自动聚焦-focus
  • 点击当前节点范围

当以上三点发生一项,节点对应的data都要isEdit = false;

1、enter键

<!-- tree_render component -->
<el-input @keyup.enter.native="nodeEditPass(STORE,DATA,NODE)"></el-input>

添加方法:

//tree_render component
methods: {
  nodeEditPass(s,d,n){
    d.isEdit = false;
  }
}

2、focus or blur

<!-- tree_render component -->
<el-input @blur="nodeEditPass(STORE,DATA,NODE)"></el-input>

后来发现第一次编辑时能让input聚焦,点击第二个input就不起作用了,加了autofocus属性也同样如此。所以我们要在点击编辑icon的时候,用原生的input autofocus。

修改方法:

//tree_render component
nodeEdit(s,d,n){//编辑
 d.isEdit = true;
 this.$nextTick(() => {
  this.$refs['treeInput'+d.id].$refs.input.focus()
 })
 this.$emit('nodeEdit',s,d,n)
}

3、当前节点点击

采用el-tree已有的API——node-click

<!-- el-tree component -->
<el-tree @node-click="handleNodeClick"></el-tree>

添加methods:

//el-tree component
methods: {
  handleNodeClick(d,n,s){//点击节点
   d.isEdit = false;//放弃编辑状态
  }
}

问题来了,如果在编辑状态下点击此节点也同样会影响input,这就无法进入编辑,所以要阻止input事件冒泡:

<!-- tree_render component -->
<el-input @click.stop.native="nodeEditFocus"></el-input>

添加methods:

//tree_render component
methods: {
  nodeEditFocus(){}
}

4、v-show代替v-if

这里有个新的问题,当用户经常编辑修改,v-if模板的开销更高,所以改用v-show。而后者不支持template模板,所以要适当调整一下位置:

<template>
  <span class="tree-expand">
    <span class="tree-label" v-show="DATA.isEdit">
      <el-input class="edit" size="mini" autofocus
      v-model="DATA.name"
      :ref="'treeInput'+DATA.id"
      @click.stop.native="nodeEditFocus"
      @blur="nodeEditPass(STORE,DATA,NODE)"
      @keyup.enter.native="nodeEditPass(STORE,DATA,NODE)"></el-input>
    </span>
    <span v-show="!DATA.isEdit">
      <span>{{DATA.name}}</span>
    </span>
    <span class="tree-btn" v-show="!DATA.isEdit">
      <i class="el-icon-plus" @click.stop="nodeAdd(STORE,DATA,NODE)"></i>
      <i class="el-icon-edit" @click.stop="nodeEdit(STORE,DATA,NODE)"></i>
      <i class="el-icon-delete" @click.stop="nodeDel(STORE,DATA,NODE)"></i>
    </span>
  </span>
</template>

5.增

新增节点 =》添加一条数据

  1. 新增的同时展开父节点
  2. 是否考虑无限新增
//el-tree component
handleAdd(s,d,n){//增加节点
 console.log(s,d,n)
 if(n.level >=6){
  this.$message.error("最多只支持五级!")
  return false;
 }
 //添加数据
 d.children.push({
  id: ++this.maxexpandId,
  name: '新增节点',
  pid: d.id,
  isEdit: false,
  children: []
 });
 //展开节点
 if(!n.expanded){
  n.expanded = true;
 }
}

新增节点字体加粗 =》给节点添加一个class =》 如何判断是否新增?

我们有一个参数maxexpandId

tree_render添加一个prop

//el-tree component
renderContent(h,{node,data,store}){//加载节点
 let that = this;
 return h(TreeRender,{
  props: {
   ...
   maxexpandId: that.non_maxexpandId
  },
  on: {...}
 });
}

根据id判断:

//tree_render component
props: ['NODE', 'DATA', 'STORE', 'maxexpandId']
<!-- tree_render component -->
<span v-show="!DATA.isEdit" 
:class="[DATA.id > maxexpandId ? 'tree-new tree-label' : 'tree-label']"
:ref="'treeLabel'+DATA.id">
  <span>{{DATA.name}}</span>
</span>
.tree-expand .tree-label.tree-new{
  font-weight:600;
}

6.删

跟新增同义:删除节点 =》删除一条数据

  • 新增节点直接删除
  • 已有节点需提示再删除
  • 已有子级节点不能删除
handleDelete(s,d,n){//删除节点
 console.log(s,d,n)
 let that = this;
 //有子级不删除
 if(d.children && d.children.length !== 0){
  this.$message.error("此节点有子级,不可删除!")
  return false;
 }else{
  //删除操作
  let delNode = () => {
   let list = n.parent.data.children || n.parent.data,
   //节点同级数据,顶级节点时无children
    _index = 99999;//要删除的index
   list.map((c,i) => {
    if(d.id == c.id){
     _index = i;
    }
   })
   let k = list.splice(_index,1);
   //console.log(_index,k)
   this.$message.success("删除成功!")
  }
  let isDel = () => {
   that.$confirm("是否删除此节点?","提示",{
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning"
   }).then(() => {
    delNode()//此处可通过ajax做删除操作
   }).catch(() => {
    return false;
   })
  }
  //新增节点直接删除,否则要通过请求数据删除
  d.id > this.non_maxexpandId ? delNode() : isDel()
 }
}

7.拓展

还有一些特别的需求,例如:

1、点击高亮的时候显示icon

.expand-tree .is-current>.el-tree-node__content .tree-btn,
.expand-tree .el-tree-node__content:hover .tree-btn{
 display: inline-block;
}

2、添加顶级节点

添加按钮:

<!-- el-tree component -->
<el-button @click="handleAddTop">添加顶级节点</el-button>

添加methods:

//el-tree component
methods: {
 handleAddTop(){
  this.setTree.push({
   id: ++this.maxexpandId,
   name: '新增节点',
   pid: '',
   isEdit: false,
   children: []
  })
 }
}

3、默认展开树形第一级

//el-tree component
mounted(){
 this.initExpand()
},
methods: {
 initExpand(){
  //isLoadingTree用意也是在此
  this.setTree.map((a) => {
   this.defaultExpandKeys.push(a.id)
  });
  this.isLoadingTree = true;
 },
}

8.github

还有些具体的样式都放在github了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
THREE.JS入门教程(4)创建粒子系统
Jan 24 Javascript
js 固定悬浮效果实现思路代码
Aug 02 Javascript
extjs 如何给column 加上提示
Jul 29 Javascript
js实现下拉列表选中某个值的方法(3种方法)
Dec 17 Javascript
基于jquery实现图片放大功能
May 07 Javascript
JavaScript基础语法之js表达式
Jun 07 Javascript
轻松实现js弹框显示选项
Sep 13 Javascript
详解webpack3编译兼容IE8的正确姿势
Dec 21 Javascript
jQuery实现标签子元素的添加和赋值方法
Feb 24 jQuery
使用Angular CLI进行Build(构建)和Serve详解
Mar 24 Javascript
JavaScript中this的学习笔记及用法整理
Feb 17 Javascript
如何利用React实现图片识别App
Feb 18 Javascript
vue-router实现tab标签页(单页面)详解
Oct 17 #Javascript
BACKBONE.JS 简单入门范例
Oct 17 #Javascript
JS获取一个表单字段中多条数据并转化为json格式
Oct 17 #Javascript
JS解决position:sticky的兼容性问题的方法
Oct 17 #Javascript
JS实现div模块的截图并下载功能
Oct 17 #Javascript
bootstrap模态框嵌套、tabindex属性、去除阴影的示例代码
Oct 17 #Javascript
AngularJS 控制器 controller的详解
Oct 17 #Javascript
You might like
PHP个人网站架设连环讲(一)
2006/10/09 PHP
用Php编写注册后Email激活验证的实例代码
2013/03/11 PHP
phpize的深入理解
2013/06/03 PHP
PHP类的自动加载机制实现方法分析
2019/01/10 PHP
基于ThinkPHP删除目录及目录文件函数
2020/10/28 PHP
在JavaScript中使用inline函数的问题
2007/03/08 Javascript
js wmp操作代码小结(音乐连播功能)
2008/11/08 Javascript
javascript 节点遍历函数
2010/03/28 Javascript
jQuery ui插件的使用方法代码实例
2013/05/08 Javascript
在JavaScript中重写jQuery对象的方法实例教程
2014/08/25 Javascript
JavaScript实现跟随滚动缓冲运动广告框
2017/07/15 Javascript
js 两个日期比较相差多少天的实例
2017/10/19 Javascript
生产制造追溯系统之再说条码打印
2019/06/03 Javascript
解决layui 表单元素radio不显示渲染的问题
2019/09/04 Javascript
详解从vue-loader源码分析CSS Scoped的实现
2019/09/23 Javascript
[02:23]完美世界全国高校联赛街访DOTA2第一期
2019/11/28 DOTA
python实现查询IP地址所在地
2015/03/29 Python
对于Python异常处理慎用“except:pass”建议
2015/04/02 Python
Python multiprocessing模块中的Pipe管道使用实例
2015/04/11 Python
Python入门之modf()方法的使用
2015/05/15 Python
Python基于pygame实现的弹力球效果(附源码)
2015/11/11 Python
一篇文章彻底搞懂Python中可迭代(Iterable)、迭代器(Iterator)与生成器(Generator)的概念
2019/05/13 Python
python多线程同步之文件读写控制
2021/02/25 Python
Python实现快速排序的方法详解
2019/10/25 Python
Pandas之read_csv()读取文件跳过报错行的解决
2020/04/21 Python
学习python需要有编程基础吗
2020/06/02 Python
CSS Grid布局教程之什么是网格布局
2014/12/30 HTML / CSS
HTML5 本地存储 LocalStorage详解
2016/06/24 HTML / CSS
莫斯科绝对前卫最秘密的商店:SVMoscow
2017/10/23 全球购物
英国领先的在线礼品店:Getting Personal
2019/09/24 全球购物
香奈儿美国官网:CHANEL美国
2020/05/20 全球购物
留学自荐信的技巧
2013/10/17 职场文书
文明礼仪事迹材料
2014/01/09 职场文书
党员承诺书范文
2014/05/19 职场文书
Java Spring 控制反转(IOC)容器详解
2021/10/05 Java/Android
java版 简单三子棋游戏
2022/05/04 Java/Android