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中两个感叹号的作用说明
Dec 28 Javascript
JS实现简易图片轮播效果的方法
Mar 25 Javascript
AngularJS中如何使用echart插件示例详解
Oct 26 Javascript
深入理解Vue.js源码之事件机制
Sep 27 Javascript
react-native中ListView组件点击跳转的方法示例
Sep 30 Javascript
Vue实战之vue登录验证的实现代码
Oct 31 Javascript
JavaScript实现计算圆周率到小数点后100位的方法示例
May 08 Javascript
Vue中的混入的使用(vue mixins)
Jun 01 Javascript
webpack4 处理CSS的方法示例
Sep 03 Javascript
解决JavaScript中0.1+0.2不等于0.3问题
Oct 23 Javascript
为vue项目自动设置请求状态的配置方法
Jun 09 Javascript
Vue脚手架编写试卷页面功能
Mar 17 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
Array of country list in PHP with Zend Framework
2011/10/17 PHP
php动态生成缩略图并输出显示的方法
2015/04/20 PHP
ThinkPHP使用getlist方法实现数据搜索功能示例
2017/05/08 PHP
PHP rmdir()函数的用法总结
2019/07/02 PHP
JavaScript中this关键字使用方法详解
2007/03/08 Javascript
一些常用弹出窗口/拖放/异步文件上传等实用代码
2013/01/06 Javascript
现如今最流行的JavaScript代码规范
2014/03/08 Javascript
JavaScript分秒倒计时器实现方法
2015/02/02 Javascript
JS中showModalDialog关闭子窗口刷新主窗口用法详解
2017/03/25 Javascript
实例分析js事件循环机制
2017/12/13 Javascript
vue中阻止click事件冒泡,防止触发另一个事件的方法
2018/02/08 Javascript
JavaScript设计模式之单例模式简单实例教程
2018/07/02 Javascript
jsonp格式前端发送和后台接受写法的代码详解
2019/11/07 Javascript
使用vue重构资讯页面的实例代码解析
2019/11/26 Javascript
jQuery实现消息弹出框效果
2019/12/10 jQuery
js实现贪吃蛇游戏 canvas绘制地图
2020/09/09 Javascript
python 装饰器功能以及函数参数使用介绍
2012/01/27 Python
Python 40行代码实现人脸识别功能
2017/04/02 Python
基于Django filter中用contains和icontains的区别(详解)
2017/12/12 Python
PyTorch上搭建简单神经网络实现回归和分类的示例
2018/04/28 Python
使用CodeMirror实现Python3在线编辑器的示例代码
2019/01/14 Python
python 实现矩阵上下/左右翻转,转置的示例
2019/01/23 Python
Python 监测文件是否更新的方法
2019/06/10 Python
Python CVXOPT模块安装及使用解析
2019/08/01 Python
Python学习笔记之迭代器和生成器用法实例详解
2019/08/08 Python
Python多线程多进程实例对比解析
2020/03/12 Python
使用Python获取爱奇艺电视剧弹幕数据的示例代码
2021/01/12 Python
突袭HTML5之Javascript API扩展1—Web Worker异步执行及相关概述
2013/01/31 HTML / CSS
美国女性奢华品牌精品店:INTERMIX
2017/10/12 全球购物
阿迪达斯越南官网:adidas越南
2020/07/19 全球购物
物业总经理助理岗位职责
2014/06/29 职场文书
村委会贫困证明范文
2014/09/21 职场文书
大学生国庆节65周年演讲稿范文
2014/09/25 职场文书
2014年机关工会工作总结
2014/12/19 职场文书
《战锤40K:暗潮》跳票至9月 公布新宣传片
2022/04/03 其他游戏
vue项目打包后路由错误的解决方法
2022/04/13 Vue.js