vue递归组件实战之简单树形控件实例代码


Posted in Javascript onAugust 27, 2019

1、递归组件-简单树形控件预览及问题

vue递归组件实战之简单树形控件实例代码 

在编写树形组件时遇到的问题:

  • 组件如何才能递归调用?
  • 递归组件点击事件如何传递?

2、树形控件基本结构及样式

<template>
 <ul class="vue-tree">
  <li class="tree-item">
   <div class="tree-content"><!--节点内容-->
    <div class="expand-arrow"></div><!--展开或收缩节点按钮-->
    <div class="tree-label">小学</div><!--节点文本内容-->
   </div>
   <ul class="sub-tree"><!--子节点-->
    <li class="tree-item expand">
     <div class="tree-content">
      <div class="expand-arrow"></div>
      <div class="tree-label">语文</div>
     </div>
    </li>
    <li class="tree-item">
     <div class="tree-content">
      <div class="expand-arrow"></div>
      <div class="tree-label">数学</div>
     </div>
    </li>
   </ul>
  </li>
 </ul>
</template>

<style lang="stylus">
.vue-tree{
 list-style: none;
 padding: 0;
 margin: 0;
 .tree-item{
  cursor: pointer;
  transition: background-color .2s;
  .tree-content{
   position: relative;
   padding-left: 28px;
   &:hover{
    background-color: #f0f7ff;
   }
  }
  .expand-arrow{
   position: absolute;
   top: 0;
   left: 0;
   width: 28px;
   height: 28px;
   cursor: pointer;
   &::after{
    position: absolute;
    top: 50%;
    left: 50%;
    display: block;
    content: ' ';
    border-width: 5px;
    border-style: solid;
    border-color: transparent;
    border-left-color: #ccc;
    margin: -5px 0 0 -2.5px;
    transition: all .2s;
   }
  }
  &.expand{
   &>.tree-content{
    background-color: #f0f7ff;
    &>.expand-arrow{
     &::after{
      transform: rotate(90deg);
      margin: -2.5px 0 0 -5px;
     }
    }
   }
  }
  .tree-label{
   height: 28px;
   line-height: 28px;
   font-size: 14px;
  }
  .sub-tree{
   display: none;
   list-style: none;
   padding: 0 0 0 28px;
   margin: 0;
  }
  &.expand>.sub-tree{
   display: block;
  }
  &.no-child{
   &>.tree-content{
    &>.expand-arrow{
     display: none;
    }
   }
  }
 }
}
</style>

3、组件目录及数据结构

目录结构

vue-tree

VueTree.vue
TreeItem.vue

树形控件数据结构

let treeData = [
 {
  text: "一级", // 显示的文字
  expand: false, // 默认是否展开
  children: [ // 子节点
   {
    text: "一级-1",
    expand: false,
   },
   {
    text: "一级-2",
    expand: false,
    children: [
     {
      text: "一级-2-1",
      expand: false,
     },
     {
      text: "一级-2-2",
      expand: false,
     }
    ]
   }
  ]
 }
];

3.1、 TreeItem.vue 代码

<template>
 <li class="tree-item" :class="{expand: isExpand, 'no-child': !treeItemData.children || treeItemData.children.length === 0}">
  <div class="tree-content" @click="_clickEvent">
   <div class="expand-arrow" @click.stop="expandTree()"></div>
   <div class="tree-label">{{treeItemData.text}}</div>
  </div>
  <ul class="sub-tree" v-if="treeItemData.children && treeItemData.children.length > 0">
   <!--TreeItem组件中调用TreeItem组件-->
   <TreeItem
    v-for="item in treeItemData.children"
    :tree-item-data="item"
    :key="uuid()"
    :tree-click-event="treeClickEvent"></TreeItem>
  </ul>
 </li>
</template>

<script>
 export default {
  name: "TreeItem",
  props: {
   treeItemData: {
    type: Object,
    default(){
     return {};
    }
   },
   // 节点点击事件
   treeClickEvent: {
    type: Function,
    default() {
     return function () {};
    }
   }
  },
  data(){
   return {
    // 节点是否展开
    isExpand: this.treeItemData.expand || false
   }
  },
  methods: {
   // 展开/收缩
   expandTree(flag){
    if(!this.treeItemData.children || this.treeItemData.children.length === 0){
     return;
    }
    if(typeof flag === 'undefined'){
     flag = !this.isExpand;
    }else{

     flag = !!flag;
    }
    this.isExpand = flag;
   },
   // 创建一个唯一id
   uuid(){
    let str = Math.random().toString(32);
    str = str.substr(2);
    return str;
   },
   // 节点点击事件
   _clickEvent(){
    // 如果有传递事件函数,则调用事件函数并传递当前节点数据及组件
    if(this.treeClickEvent && typeof this.treeClickEvent === 'function'){
     this.treeClickEvent(this.treeItemData, this);
    }
   }
  }
 }
</script>

3.1.1、解决 组件如何才能递归调用? 问题

在组件模板内调用自身 必须明确定义组件的name属性 ,并且递归调用时组件名称就是name属性。如在 TreeItem.vue 组件中组件的name名称为'TreeItem',那么在template中调用时组件名称就必须是 <TreeItem> 。

当然也可以全局注册组件,具体可以查看vue官方文档 递归组件

3.1.2、解决 递归组件点击事件如何传递? 问题

我这里的解决方案是使用 props 将事件函数传递进来,在点击节点的时候调用事件函数,并把相应的数据传递进去。

之前也尝试过使用 $emit 的形式并把数据传递过去,由于是递归组件,这样一直 $emit ,到最外层时传递的数据就变了,比如传递是第3层节点的数据,到最后执行时数据就变成第1层节点的数据了

4、 VueTree.vue 组件

<template>
 <ul class="vue-tree">
  <TreeItem
    v-for="(item, index) in treeData"
    :key="index"
    :treeItemData="item"
    :tree-click-event="treeClickEvent"></TreeItem>
 </ul>
</template>

<script>
 import TreeItem from "./TreeItem";
 export default {
  name: "VueTreeMenu",
  components: {
   TreeItem
  },
  props: {
   // 树形控件数据
   treeData: {
    type: Array,
    default(){
     return [];
    }
   },
   // 节点点击事件
   treeClickEvent: {
    type: Function,
    default() {
     return function () {};
    }
   }
  }
 }
</script>

<style lang="stylus">
.vue-tree{
 list-style: none;
 padding: 0;
 margin: 0;
 .tree-item{
  cursor: pointer;
  transition: background-color .2s;
  .tree-content{
   position: relative;
   padding-left: 28px;
   &:hover{
    background-color: #f0f7ff;
   }
  }
  .expand-arrow{
   position: absolute;
   top: 0;
   left: 0;
   width: 28px;
   height: 28px;
   cursor: pointer;
   &::after{
    position: absolute;
    top: 50%;
    left: 50%;
    display: block;
    content: ' ';
    border-width: 5px;
    border-style: solid;
    border-color: transparent;
    border-left-color: #ccc;
    margin: -5px 0 0 -2.5px;
    transition: all .2s;
   }
  }
  &.expand{
   &>.tree-content{
    background-color: #f0f7ff;
    &>.expand-arrow{
     &::after{
      transform: rotate(90deg);
      margin: -2.5px 0 0 -5px;
     }
    }
   }
  }
  .tree-label{
   height: 28px;
   line-height: 28px;
   font-size: 14px;
  }
  .sub-tree{
   display: none;
   list-style: none;
   padding: 0 0 0 28px;
   margin: 0;
  }
  &.expand>.sub-tree{
   display: block;
  }
  &.no-child{
   &>.tree-content{
    /*padding-left: 0;*/
    &>.expand-arrow{
     display: none;
    }
   }
  }
 }
}
</style>

5、使用树形组件

<template>
 <div class="app" id="app">
  <VueTree :tree-data="treeData2" :tree-click-event="treeClickEvent"></VueTree>
 </div>
</template>

<script>
import VueTree from "./components/vue-tree/VueTree";

export default {
 name: 'app',
 data(){
  return {
   treeData2: [
    {
     text: "一级", // 显示的文字
     expand: false, // 默认是否展开
     children: [
      {
       text: "二级-1",
       expand: false,
      },
      {
       text: "二级-2",
       expand: false,
       children: [
        {
         text: "三级-1",
         expand: false,
        },
        {
         text: "三级-2",
         expand: false,
         children: [
          {
           text: "四级-1",
           expand: false,
          }
         ]
        }
       ]
      }
     ]
    },
    {
     text: "一级-2",
     expand: false
    }
   ]
  }
 },
 methods: {
  treeClickEvent(item, treeItem){
   console.log(item);
  }
 },
 components: {
  VueTree
 }
}
</script>

总结

以上所述是小编给大家介绍的vue递归组件实战之简单树形控件实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
Js 刷新框架页的代码
Apr 13 Javascript
jquery插件制作 提示框插件实现代码
Aug 17 Javascript
用js实现trim()的解决办法
Apr 16 Javascript
js操作iframe父子窗体示例
May 22 Javascript
JS网页在线获取鼠标坐标值的方法
Feb 28 Javascript
js实现彩色条纹滚动条效果
Mar 15 Javascript
vuejs使用$emit和$on进行组件之间的传值的示例
Oct 04 Javascript
vue-awesome-swiper滑块插件使用方法详解
Nov 27 Javascript
浅析node.js的模块加载机制
May 25 Javascript
JS实现的全选、全不选及反选功能【案例】
Feb 19 Javascript
Vue使用JSEncrypt实现rsa加密及挂载方法
Feb 07 Javascript
Element Badge标记的使用方法
Jul 27 Javascript
vue项目中引入Sass实例方法
Aug 27 #Javascript
package.json配置文件构成详解
Aug 27 #Javascript
axios如何利用promise无痛刷新token的实现方法
Aug 27 #Javascript
解决vue打包后刷新页面报错:Unexpected token
Aug 27 #Javascript
JS用最简单的方法实现四舍五入
Aug 27 #Javascript
微信小程序模板消息推送的两种实现方式
Aug 27 #Javascript
vue实现codemirror代码编辑器中的SQL代码格式化功能
Aug 27 #Javascript
You might like
关于时间计算的结总
2006/12/06 PHP
php实现断点续传大文件示例代码
2020/06/19 PHP
JavaScript 一行代码,轻松搞定浮动快捷留言-V2升级版
2010/04/02 Javascript
javascript判断非数字的简单例子
2013/07/18 Javascript
js插件Jcrop自定义截取图片功能
2016/10/14 Javascript
JavaScript 中 avalon绑定属性总结
2016/10/19 Javascript
Angular 4.x 动态创建表单实例
2017/04/25 Javascript
详解vue项目中如何引入全局sass/less变量、function、mixin
2018/06/02 Javascript
解析vue路由异步组件和懒加载案例
2018/06/08 Javascript
element-ui table span-method(行合并)的实现代码
2018/12/20 Javascript
taro小程序添加骨架屏的实现代码
2019/11/15 Javascript
[03:44]2014DOTA2国际邀请赛 71专访:DK战队赛前讨论视频遭泄露
2014/07/13 DOTA
[06:43]DAC2018 4.5 SOLO赛 Maybe vs Paparazi
2018/04/06 DOTA
使用Node.js和Socket.IO扩展Django的实时处理功能
2015/04/20 Python
Python 12306抢火车票脚本
2018/02/07 Python
将python图片转为二进制文本的实例
2019/01/24 Python
python opencv对图像进行旋转且不裁剪图片的实现方法
2019/07/09 Python
Python操作excel的方法总结(xlrd、xlwt、openpyxl)
2019/09/02 Python
将pytorch转成longtensor的简单方法
2020/02/18 Python
python实现二分类和多分类的ROC曲线教程
2020/06/15 Python
了解一下python内建模块collections
2020/09/07 Python
Python json解析库jsonpath原理及使用示例
2020/11/25 Python
HTML5 canvas 瀑布流文字效果的示例代码
2018/01/31 HTML / CSS
班级聚会策划书
2014/01/16 职场文书
老师的检讨书
2014/02/23 职场文书
绿色城市实施方案
2014/03/19 职场文书
财务内勤岗位职责
2014/04/17 职场文书
2014年党员承诺书范文
2014/05/20 职场文书
中学生关于梦想的演讲稿
2014/08/22 职场文书
假释思想汇报范文
2014/10/11 职场文书
丽江古城导游词
2015/02/03 职场文书
2015年办公室主任工作总结
2015/04/09 职场文书
2015年监理个人工作总结
2015/05/23 职场文书
个人催款函范文
2015/06/23 职场文书
MySQL系列之七 MySQL存储引擎
2021/07/02 MySQL
大脑的记忆过程在做数据压缩,不同图形也有共同的记忆格式
2022/04/29 数码科技