Vue.js递归组件构建树形菜单


Posted in Javascript onDecember 24, 2017

在Vue.js中一个递归组件调用的是其本身,如:

Vue.component('recursive-component', {
 template: `<!--Invoking myself!-->
    <recursive-component></recursive-component>
 });

递归组件常用于在blog上显示注释、嵌套的菜单,或者基本上是父和子相同的类型,尽管具体内容不同。例如:

Vue.js递归组件构建树形菜单

现在给您演示一下如何有效地使用递归组件,我将通过建立一个可扩展/收缩的树形菜单的来一步步进行。

数据结构

一个树状UI的递归组件将是一些递归数据结构的可视化表达。在本教程中,我们将使用树状结构,其中每个节点都是一个对象:

一个 label 属性。

如果它有子节点,一个 nodes 属性,则它是一个或多个节点的数组属性。

与所有树结构一样,它必须有一个根节点,但可以无限深。

let tree = {
 label: 'root',
 nodes: [
  {
  label: 'item1',
  nodes: [
   {
   label: 'item1.1'
   },
   {
   label: 'item1.2',
   nodes: [
    {
    label: 'item1.2.1'
    }
   ]
   }
  ]
  }, 
  {
  label: 'item2' 
  }
 ]
 }

递归组件

让我们做一个递归组件来显示我们的称为 TreeMenu 的数据结构。它只显示当前节点的标签,并调用自己来显示任何子节点。文件名:TreeMenu.vue,内容如下:

<template>
 <div class="tree-menu">
  <div>{{ label }}</div>
  <tree-menu 
  v-for="node in nodes" 
  :nodes="node.nodes"
  :label="node.label"
  >
  </tree-menu>
 </div>
 </template>
 <script>
 export default { 
  props: [ 'label', 'nodes' ],
  name: 'tree-menu'
 }
 </script>

如果你使用一个组件递归,必须先给 Vue.component 做一个全局的定义,或者,给它一个 name 属性。否则,任何子组件将无法进一步调用它,你会得到一个不确定的“undefined component error”的错误提示。

基本事件

与任何递归函数一样,你需要一个基本事件来结束递归,否则渲染将无限期地继续下去,最终会导致堆栈溢出。

在树菜单中,当我们到达一个没有子节点的节点的时候,我们希望停止递归。你能通过 v-if 做到这一功能,但我们选择使用 v-for 将隐式地为我们实现它;如果 nodes 数组没有任何进一步的定义 tree-menu 组件将被调用。template.vue文件如下:

<template>
 <div class="tree-menu">
  ...
  <!--If `nodes` is undefined this will not render-->
  <tree-menu v-for="node in nodes"></tree-menu>
 </template>

使用用法

我们现在如何使用这个组件?首先,我们声明一个Vue实例,具有一个数据结构包括data属性和定义过的treemenu组件。app.js文件如下:

import TreeMenu from './TreeMenu.vue'
 let tree = {
 ...
 }
 new Vue({
 el: '#app',
 data: {
  tree
 },
 components: {
  TreeMenu
 }
 })

请记住,我们的数据结构有一个根节点。我们在主模板开始递归调用 TreeMenu 组件,使用根 nodes 属性来props:

<div id="app">
 <tree-menu :label="tree.label" :nodes="tree.nodes"></tree-menu>
 </div>

下面是它目前的样子:

Vue.js递归组件构建树形菜单

正确的姿势

在视觉上识别子组件的“深度”是很好的,这样用户就可以从UI中获得数据结构的感觉。让我们缩进每一层的子节点来实现这个目标。

Vue.js递归组件构建树形菜单

这是通过增加一个depth prop定义,通过 TreeMenu 来实现。我们将使用这个值动态地将内联样式与转换绑定在一起:将使用transform: translate的CSS规则为每个节点的标签,从而创建缩进。template.vue修改如下**:**

<template>
 <div class="tree-menu">
  <div :style="indent">{{ label }}</div>
  <tree-menu 
  v-for="node in nodes" 
  :nodes="node.nodes" 
  :label="node.label"
  :depth="depth + 1"
  >
  </tree-menu>
 </div>
 </template>
 <script>
 export default { 
  props: [ 'label', 'nodes', 'depth' ],
  name: 'tree-menu',
  computed: {
  indent() {
   return { transform: `translate(${this.depth * 50}px)` }
  }
  }
 }
 </script>

depth 属性在主模板中从零开始。在上面的组件模板中,你可以看到每次传递到任何子节点时这个值都会递增。

<div id="app">
 <tree-menu 
  :label="tree.label" 
  :nodes="tree.nodes"
  :depth="0"
 ></tree-menu>
 </div>

注意:记得 v-bind depth值以确保它是一个JavaScript数字类型而不是字符串。

展开/收起

由于递归数据结构可能很大,所以显示它们的一个很好的UI技巧是隐藏除根节点以外的所有节点,以便用户可以根据需要展开或收起节点。

为此,我们将增加一个局部属性showChildren 。如果他的值为False,子节点将不会被渲染。此值应通过点击节点切换,所以我们需要使用一个单击事件的监听器方法 toggleChildren 来进行管理。template.vue文件修改如下**:**

<template>
 <div class="tree-menu">
  <div :style="indent" @click="toggleChildren">{{ label }}</div>
  <tree-menu 
  v-if="showChildren"
  v-for="node in nodes" 
  :nodes="node.nodes" 
  :label="node.label"
  :depth="depth + 1"
  >
  </tree-menu>
 </div>
 </template>
 <script>
 export default { 
  props: [ 'label', 'nodes', 'depth' ],
  data() {
  return { showChildren: false }
  },
  name: 'tree-menu',
  computed: {
  indent() {
   return { transform: `translate(${this.depth * 50}px)` }
  }
  },
  methods: {
  toggleChildren() {
   this.showChildren = !this.showChildren;
  }
  }
 }
 </script>

总结

这样,我们就有了一个工作树菜单。用来画龙点睛的一个方法是,你可以添加一个加号/减号图标,这样可以使UI的显示更加明显。我还增加了的很好的字体和计算性能在原来 showChildren 的基础上。

Vue.js递归组件构建树形菜单

Javascript 相关文章推荐
jquery根据锚点offset值实现动画切换
Sep 11 Javascript
node.js中的fs.appendFileSync方法使用说明
Dec 17 Javascript
JS实现带动画的回到顶部效果
Dec 28 Javascript
js推箱子小游戏步骤代码解析
Jan 10 Javascript
Vue的事件响应式进度条组件实例详解
Feb 04 Javascript
vue生成文件本地打开查看效果的实例
Sep 06 Javascript
node.js 基于cheerio的爬虫工具的实现(需要登录权限的爬虫工具)
Apr 10 Javascript
Bootstrap 时间日历插件bootstrap-datetimepicker配置与应用小结
May 28 Javascript
javascript写一个ajax自动拦截并下载数据代码实例
Sep 07 Javascript
JavaScrip如果基于url实现图片下载
Jul 03 Javascript
react-intl实现React国际化多语言的方法
Sep 27 Javascript
vue.js 使用原生js实现轮播图
Apr 26 Vue.js
深入浅析JSONAPI在PHP中的应用
Dec 24 #Javascript
Parcel.js + Vue 2.x 极速零配置打包体验教程
Dec 24 #Javascript
jquery中ajax请求后台数据成功后既不执行success也不执行error的完美解决方法
Dec 24 #jQuery
解决Vue 浏览器后退无法触发beforeRouteLeave的问题
Dec 24 #Javascript
通过fastclick源码分析彻底解决tap“点透”
Dec 24 #Javascript
anime.js 实现带有描边动画效果的复选框(推荐)
Dec 24 #Javascript
vue项目常用组件和框架结构介绍
Dec 24 #Javascript
You might like
PHP正则替换函数preg_replace和preg_replace_callback使用总结
2014/09/22 PHP
php判断是否连接上网络的方法实例详解
2016/12/14 PHP
PHP 观察者模式深入理解与应用分析
2019/09/25 PHP
使用PHP+Redis实现延迟任务,实现自动取消订单功能
2019/11/21 PHP
Laravel统一错误处理为JSON的方法介绍
2020/10/18 PHP
JS控件autocomplete 0.11演示及下载 1月5日已更新
2007/01/09 Javascript
ext combox 下拉框不出现自动提示,自动选中的解决方法
2010/02/24 Javascript
19个很有用的 JavaScript库推荐
2011/06/27 Javascript
js Date概念详细介绍
2013/11/22 Javascript
node.js读取文件到字符串的方法
2015/06/29 Javascript
jQuery检测某个元素是否存在代码分享
2015/07/09 Javascript
QQ登录背景闪动效果附效果演示源码下载
2015/09/22 Javascript
总结JavaScript中布尔操作符||与&amp;&amp;的使用技巧
2015/11/17 Javascript
jQuery实现点击按钮文字变成input框点击保存变成文字
2016/05/09 Javascript
JavaScript sort数组排序方法和自我实现排序方法小结
2016/06/06 Javascript
浅谈bootstrap使用中的一些问题以及解决过程
2016/10/18 Javascript
用jQuery实现优酷首页轮播图
2017/01/09 Javascript
推荐三款日期选择插件(My97DatePicker、jquery.datepicker、Mobiscroll)
2017/04/21 jQuery
JavaScript函数IIFE使用详解
2019/10/21 Javascript
推荐下python/ironpython:从入门到精通
2007/10/02 Python
Python实现抓取页面上链接的简单爬虫分享
2015/01/21 Python
用Python代码来绘制彭罗斯点阵的教程
2015/04/03 Python
Python实现二维数组按照某行或列排序的方法【numpy lexsort】
2017/09/22 Python
Python三种遍历文件目录的方法实例代码
2018/01/19 Python
用pycharm开发django项目示例代码
2018/10/24 Python
Python如何调用外部系统命令
2019/08/07 Python
python中的反斜杠问题深入讲解
2019/08/12 Python
Scrapy实现模拟登录的示例代码
2021/02/21 Python
Sofft鞋官网:世界知名鞋类品牌
2017/03/28 全球购物
波兰多品牌运动商店:StreetStyle24.pl
2020/09/22 全球购物
致垒球运动员加油稿
2014/02/16 职场文书
员工安全生产责任书
2014/07/22 职场文书
高中国旗下的演讲稿
2014/08/28 职场文书
Python还能这么玩之只用30行代码从excel提取个人值班表
2021/06/05 Python
详解overflow:hidden的作用(溢出隐藏、清除浮动、解决外边距塌陷)
2021/07/01 HTML / CSS
Python时间操作之pytz模块使用详解
2022/06/14 Python