Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现


Posted in Javascript onApril 01, 2019

写在前面

首先,本篇文章所开发的组件并非一个已经开源的上线组件,所以如果你急于需要一个插件来只做你的项目,那么并不能带给你及时的帮助。这个组件的开发预计写两篇文章,一遍写组件,一篇写组件逻辑。这篇文章也是我自己开发的从无到有的过程,所以它可以为你提供一些Tree组件开发的思路,代码写到一定程度,不能完全依赖插件了,有时间可以看看插件源码或者动手去开发,这样真的能加深对技术的掌握程度。

开发过程

1.数据仓库-Vuex

2.组件的循环创建-递归组件

需求决定了我的技术选型,项目需求是一个中国各级政府列表的选择,后台基于大数据去汇总各级政府网站的文章决策,然后交给前端去展示,左侧显示各级政府的Tree,右侧显示具体文章。因为政府数据的不确定性,所以显示政府的Tree的每一层级也是动态获取的,就比如北京市下级的海淀区政府在一小时前可能不存在某某政策文章,那么北京市节点的子节点中就不会包含海淀区这一子节点,但是10分钟前网站发布了一篇文章,那么就需要在北京市中添加海淀区,为了良好的实时性效果,每一级的子节点都不固定。

因此 树状结构的data是变化的而不是在初始化的时候就固定好 的,数据驱动Dom的思想,data有多少层级,Dom就有多少层级,data不定,所以Dom也无法提前定义好层级,决定采用Vue的递归组件,组件递归自身实现无限制层级的渲染。需求中每一个节点的Tree都具有增删改的功能,因为data是单例的,全局维护着一个data数据源头,增删改也就是操作data第n个子节点的某个子元素,因此采用了Vuex作为一个data存放的仓库( 这不是一个组件库,只是一个项目的应用 )。

项目的关键点:

1.动态加载子节点,也就是说页面加载的时候,根节点的 nodes 子节点数组可能是个空数组,每次单击节点去获取子节点数组。

2.全局单例的树节点对象 data 对象,每次得到新的子节点,需要去维护这个对象,因为数据与dom动态绑定,所以每次数据对象内部发生了变化,dom也会重绘。

vue对虚拟dom的映射通过使用diff算法进行了优化,所以不用担心,重绘造成页面闪屏

树 data 数据结构如下:

let data = {
 id: "01",
 lable: "政府机构",
 nodes: [
  {
  id: "02",
  lable: "中央机关",
  nodes: [{
   //..
  }]
  },
  {
  id: "03",
  lable: "直辖市",
  nodes: [{
   //..
   //北京市...
   //天津市..
  }]
  },
 ]
 };

显示成这样:

Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现

每一个节点包含id,label,nodes三个属性,nodes往下延伸子节点,一共有多少级不确定根据后台获取得到。

递归组件

一个简单的递归组件的示例如下:

<template>
 <div class="tree-menu">
 //组件内部不断用自身,只要子节点存在就递归调用
 <tree-menu v-for='(item, index) of dataNodes' :key='index'></tree-menu>
 </div>
</template>

<script>
export default {
 name:'TreeMenu',//组件名称必须写
 data() {
 return {
  dataNodes: {
  //...
  }
 }
 }
}
</script>

TreeMenu.vue声明组件TreeMenu,并向外暴露,在组件内部调用自身,也就是一个递归的思想,绑定的dataNodes有多少层级,那就会递归多少层,因为每一层都有v-for都会循环子节点。绑定具体数据的时候再具体分析。不断调用自身,当然这只是一个例子,实际情况还要改造一下:

新建TreeMenu.vue,作为显示节点的逻辑组件:

<template>
 <div class="tree-menu">
 <div>{{label}}</div>//节点名称
 <tree-menu //如果nodes.length>0就递归显示子节点
  v-for="(node, index) of nodes" 
  :key="index" 
  :nodes="node.nodes" //子节点的子节点向下传递
  :label="node.label"
 >
 </tree-menu>
 </div>
</template>

<script>
export default {
 name: "TreeMenu",
 props:['label','nodes'],//数据通过pros向下传递,全局唯一数据源
 data() {
 return {}; 
 }
};
</script>

创建Tree.vue作为节点树的入口:

<template>
 <div class="tree-alone">
 <tree-menu :label="tree.label" :nodes="tree.nodes"></tree-menu>
 </div>
</template>
<script>
 import TreeMenu from './TreeMenu.vue'
 export default {
 name: 'tree',
 data() {
  return {
   tree: {
   id: "01",
   lable: "总层级",
   nodes: [
    {
    id: "02",
    label: "层级1",
    nodes: [{
     label: '层级1-1'
    }]
    },
    {
    id: "03",
    label: "层级2",
    nodes: []
    },
   ]
   };
 }
  }
 },
 components: {
  TreeMenu
 }
 }
</script>

在Tree.vue入口组件里引入子组件TreeMenu.vue,并且向子组件传递数据label和nodes,这里data先预定义一个简单的对象,后面会动态获取。

TreeMenu.vue作为树形菜单组件,负责递归和数据渲染,它会接受来自入口组件传递来的label和nodes数据,进行渲染, 并且继续递归传递nodes和label 。

在从父组件接收nodes和label后,先循环渲染n个tree-menu组件,然后每一个tree-menu又会递归自身,所以数据就这样一层层向下传递nodes=>nodes.node=>nodes.node.node,此时已经完成了数据与Dom的绑定,可以修改一下Tree.vue中的tree数据源,看一下组件是否动态改变了。现在渲染如下图:

Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现

数据正确渲染,现在需要加一些样式和点击事件(展开与收缩),就不做详细介绍了,代码如下: (向下传递depth参数来获取层级索引)

//Tree.vue
<template>
 <div class="tree-alone">
 <tree-menu :label="tree.label" :nodes="tree.nodes" :depth="0"></tree-menu>
 </div>
</template>

//TreeMenu.vue
<template>
 <div class="tree-menu">
 <div :style="indent" @click="toggleChildren">{{label}}</div>
 <div v-if="showChildren">
  <tree-menu
  v-for="(item, index) of nodes"
  :key="index"
  :nodes="node.nodes"
  :label="node.label"
  :depth="depth + 1"
  ></tree-menu>
 </div>
 </div>
</template>

<script>
export default {
 name: "TreeMenu",
 props: ["label", "nodes"],
 data() {
 return {
  showChildren: false
 };
 },
 methods: {
 toggleChildren() {
  this.showChildren = !this.showChildren;
 }
 },
 computed: {
 indent() {
  return { transform: `translate(${this.depth * 20}px)` };
 }
 }
};
</script>

修改后会展开收缩与缩进,一些箭头旋转等样式问题就不详细写了。

Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现

总结

以上所述是小编给大家介绍的Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jQuery编辑器KindEditor4.1.4代码高亮显示设置教程
Mar 01 Javascript
如何让页面加载完成后执行js
Jun 26 Javascript
js 图片随机不定向浮动的实现代码
Jul 02 Javascript
JavaScript中按位“异或”运算符使用介绍
Mar 14 Javascript
详解Javascript中的Object对象
Feb 28 Javascript
Node.js的MongoDB驱动Mongoose基本使用教程
Mar 01 Javascript
JS中跨页面调用变量和函数的方法(例如a.js 和 b.js中互相调用)
Nov 01 Javascript
Bootstrap CSS布局之表格
Dec 17 Javascript
纯js的右下角弹窗实例
Mar 12 Javascript
AjaxUpLoad.js实现文件上传功能
Mar 02 Javascript
layui表格checkbox选择全选样式及功能的实例
Mar 07 Javascript
JS实现表单中点击小眼睛显示隐藏密码框中的密码
Apr 13 Javascript
基于vue框架手写一个notify插件实现通知功能的方法
Mar 31 #Javascript
基于elementUI实现图片预览组件的示例代码
Mar 31 #Javascript
微信小程序访问豆瓣电影api的实现方法
Mar 31 #Javascript
vue项目首屏打开速度慢的解决方法
Mar 31 #Javascript
jQuery事件blur()方法的使用实例讲解
Mar 30 #jQuery
Javascript实现一朵从含苞到绽放的玫瑰
Mar 30 #Javascript
使用post方法实现json往返传输数据的方法
Mar 30 #Javascript
You might like
PHP header函数分析详解
2011/08/06 PHP
PHP 字符串长度判断效率更高的方法
2014/03/02 PHP
PHP和MYSQL实现分页导航思路详解
2017/04/11 PHP
Thinkphp结合AJAX长轮询实现PC与APP推送详解
2017/07/31 PHP
php抽象方法和普通方法的区别点总结
2019/10/13 PHP
Laravel Reponse响应客户端示例详解
2020/09/03 PHP
添加JavaScript重载函数的辅助方法2
2010/07/04 Javascript
jQuery探测位置的提示弹窗(toolTip box)详细解析
2013/11/14 Javascript
Javascript前端UI框架Kit使用指南之Kitjs简介
2014/11/28 Javascript
解决微信浏览器Javascript无法使用window.location.reload()刷新页面
2016/06/21 Javascript
js完整倒计时代码分享
2016/09/18 Javascript
React Native 搭建开发环境的方法步骤
2017/10/30 Javascript
详解react阻止无效重渲染的多种方式
2018/12/11 Javascript
JavaScript中将值转换为字符串的五种方法总结
2019/06/06 Javascript
Vue.js实现可编辑的表格
2019/12/11 Javascript
原生JS实现汇率转换功能代码实例
2020/05/13 Javascript
Vue组件为什么data必须是一个函数
2020/06/11 Javascript
python使用内存zipfile对象在内存中打包文件示例
2014/04/30 Python
约瑟夫问题的Python和C++求解方法
2015/08/20 Python
Python编程实现粒子群算法(PSO)详解
2017/11/13 Python
python中in在list和dict中查找效率的对比分析
2018/05/04 Python
Python使用min、max函数查找二维数据矩阵中最小、最大值的方法
2018/05/15 Python
python模块smtplib学习
2018/05/22 Python
Python的UTC时间转换讲解
2019/02/26 Python
在python中用url_for构造URL的方法
2019/07/25 Python
如何通过python实现全排列
2020/02/11 Python
python实现将两个文件夹合并至另一个文件夹(制作数据集)
2020/04/03 Python
纪伊国屋泰国网上书店:Kinokuniya泰国
2017/12/24 全球购物
运动会通讯稿200字
2014/02/16 职场文书
数控技校生自我鉴定
2014/03/02 职场文书
厉行勤俭节约倡议书
2014/05/16 职场文书
体育馆的标语
2014/06/24 职场文书
开国大典观后感
2015/06/04 职场文书
于丹论语心得观后感
2015/06/15 职场文书
MYSQL(电话号码,身份证)数据脱敏的实现
2021/05/28 MySQL
nginx中proxy_pass各种用法详解
2021/11/07 Servers