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 相关文章推荐
常用一些Javascript判断函数
Aug 14 Javascript
JavaScript高级程序设计 阅读笔记(十四) js继承机制的实现
Aug 14 Javascript
javascript中indexOf技术详解
May 07 Javascript
跟我学习javascript的prototype原型和原型链
Nov 18 Javascript
在微信、支付宝、百度钱包实现点击返回按钮关闭当前页面和窗口的方法
Aug 05 Javascript
JavaScript每天必学之基础知识
Sep 17 Javascript
js实现年月日表单三级联动
Apr 17 Javascript
深入理解vue中slot与slot-scope的具体使用
Jan 26 Javascript
vue-router相关基础知识及工作原理
Mar 16 Javascript
vue 监听屏幕高度的实例
Sep 05 Javascript
JavaScript面向对象程序设计中对象的定义和继承详解
Jul 29 Javascript
JS的深浅复制详细
Oct 16 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&amp;mysql(三)
2006/10/09 PHP
将word转化为swf 如同百度文库般阅读实现思路及代码
2013/08/09 PHP
一个严格的PHP Session会话超时时间设置方法
2014/06/10 PHP
php中判断数组相等的方法以及数组运算符介绍
2015/03/30 PHP
Zend Framework+smarty用法实例详解
2016/03/19 PHP
phpfpm的作用和用法
2019/10/10 PHP
javascript实现简单的Map示例介绍
2013/12/23 Javascript
取消选中单选框radio的三种方式示例介绍
2013/12/23 Javascript
jQuery制作的别致导航有阴影背景高亮模式窗口
2014/04/15 Javascript
jQuery异步获取json数据方法汇总
2014/12/22 Javascript
jquery实现通用的内容渐显Tab选项卡效果
2015/09/07 Javascript
javascript中Date format(js日期格式化)方法小结
2015/12/17 Javascript
JS如何判断json是否为空
2016/07/06 Javascript
利用canvas中toDataURL()将图片转为dataURL(base64)的方法详解
2017/11/20 Javascript
Node层模拟实现multipart表单的文件上传示例
2018/01/02 Javascript
详解Vue之父子组件传值
2019/04/01 Javascript
微信小程序按钮点击动画效果的实现
2019/09/04 Javascript
javascript实现摄像头拍照预览
2019/09/30 Javascript
element-ui tooltip修改背景颜色和箭头颜色的实现
2019/12/16 Javascript
如何使用three.js 制作一个三维的推箱子游戏
2020/07/29 Javascript
Python实现测试磁盘性能的方法
2015/03/12 Python
使用Python写一个贪吃蛇游戏实例代码
2017/08/21 Python
Python基于更相减损术实现求解最大公约数的方法
2018/04/04 Python
Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能
2018/11/23 Python
Pandas 重塑(stack)和轴向旋转(pivot)的实现
2019/07/22 Python
pycharm永久激活超详细教程
2020/10/29 Python
python产生模拟数据faker库的使用详解
2020/11/04 Python
UNIONBAY官网:美国青少年服装品牌
2019/03/26 全球购物
项目经理岗位职责
2013/11/11 职场文书
上课迟到检讨书
2014/02/19 职场文书
关于孝道的演讲稿
2014/05/21 职场文书
2014年环保局工作总结
2014/12/11 职场文书
初中数学课堂教学反思
2016/02/17 职场文书
2016年法制宣传月活动总结
2016/04/01 职场文书
详解Nginx 被动检查服务器的存活状态
2021/10/16 Servers
Spring Cloud OpenFeign模版化客户端
2022/06/25 Java/Android