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 相关文章推荐
基于Jquery的标签智能验证实现代码
Dec 27 Javascript
document.documentElement的一些使用技巧
Apr 18 Javascript
js css后面所带参数含义介绍
Aug 18 Javascript
将Datatable转化成json发送前台实现思路
Sep 06 Javascript
详解JS函数重载
Dec 04 Javascript
js使用DOM设置单选按钮、复选框及下拉菜单的方法
Jan 20 Javascript
JavaScript中Array的实用操作技巧分享
Sep 11 Javascript
jQuery Ztree行政地区树状展示(点击加载)
Nov 09 Javascript
Angular.js组件之input mask对input输入进行格式化详解
Jul 10 Javascript
Web开发使用Angular实现用户密码强度判别的方法
Sep 27 Javascript
Angularjs过滤器实现动态搜索与排序功能示例
Dec 13 Javascript
vue 判断页面是首次进入还是再次刷新的实例
Nov 05 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删除非空目录的函数代码小结
2013/02/28 PHP
PHP伪静态Rewrite设置之APACHE篇
2014/07/30 PHP
PHP实现数组递归转义的方法
2014/08/28 PHP
ThinkPHP3.2.3数据库设置新特性
2015/03/05 PHP
yii分页组件用法实例分析
2015/12/28 PHP
php文档工具PHP Documentor安装与使用方法
2016/01/25 PHP
PHP实现微信提现功能(微信商城)
2019/11/21 PHP
修改发贴的编辑功能
2007/03/07 Javascript
JavaScript 学习历程和心得分享
2010/12/12 Javascript
window.open打开页面居中显示的示例代码
2013/12/27 Javascript
简单的邮箱登陆的提示效果类似于yahoo邮箱
2014/02/26 Javascript
做web开发 先学JavaScript
2014/12/12 Javascript
Javascript代码实现仿实例化类
2015/04/03 Javascript
webpack+vue.js实现组件化详解
2016/10/12 Javascript
详解Nodejs基于mongoose模块的增删改查的操作
2016/12/21 NodeJs
微信小程序 商城开发(ecshop )简单实例
2017/04/07 Javascript
Angular angular-file-upload文件上传的示例代码
2018/08/23 Javascript
基于Koa2写个脚手架模拟接口服务的方法
2018/11/27 Javascript
在vue-cli创建的项目中使用sass操作
2020/08/10 Javascript
[01:14]TI珍贵瞬间系列(六):冠军
2020/08/30 DOTA
Python编程语言的35个与众不同之处(语言特征和使用技巧)
2014/07/07 Python
Python isinstance函数介绍
2015/04/14 Python
使用Python的Django框架实现事务交易管理的教程
2015/04/20 Python
python实现装饰器、描述符
2018/02/28 Python
python3 http提交json参数并获取返回值的方法
2018/12/19 Python
Python 类属性与实例属性,类对象与实例对象用法分析
2019/09/20 Python
AmazeUI 列表的实现示例
2020/08/17 HTML / CSS
一套PHP的笔试题
2013/05/31 面试题
大学同学聚会邀请函
2014/01/19 职场文书
元旦促销方案
2014/03/15 职场文书
初中英语演讲稿
2014/04/29 职场文书
英语专业毕业论文答辩开场白
2015/05/27 职场文书
2019交通安全宣传标语集锦!
2019/06/28 职场文书
Python中使用Lambda函数的5种用法
2021/04/01 Python
golang gopm get -g -v 无法获取第三方库的解决方案
2021/05/05 Golang
Python编程源码报错解决方法总结经验分享
2021/10/05 Python