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 相关文章推荐
JavaScript 一道字符串分解的题目
Aug 03 Javascript
javascript中的缓动效果实现程序
Dec 29 Javascript
JS+JSP checkBox 全选具体实现
Jan 02 Javascript
Js 正则表达式知识汇总
Dec 02 Javascript
详解addEventListener的三个参数之useCapture
Mar 16 Javascript
javascript使用Promise对象实现异步编程
Mar 01 Javascript
BootStrap入门教程(一)之可视化布局
Sep 19 Javascript
用自定义图片代替原生checkbox实现全选,删除以及提交的方法
Oct 18 Javascript
谈谈JavaScript中浏览器兼容问题的写法小议
Dec 17 Javascript
使用vue-cli导入Element UI组件的方法
May 16 Javascript
详解React native fetch遇到的坑
Aug 30 Javascript
TypeScript实用技巧 Nominal Typing名义类型详解
Sep 23 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
PHP数组对比函数,存在交集则返回真,否则返回假
2011/02/03 PHP
解析在PHP中使用全局变量的几种方法
2013/06/24 PHP
php自定义urlencode,urldecode函数实例
2015/03/24 PHP
PHP register_shutdown_function()函数的使用示例
2015/06/23 PHP
Lazy Load 延迟加载图片的jQuery插件中文使用文档
2012/10/18 Javascript
如何用jquery控制表格奇偶行及活动行颜色
2014/04/20 Javascript
javascript函数特点实例分析
2015/05/14 Javascript
使用Object.defineProperty实现简单的js双向绑定
2016/04/15 Javascript
一系列Bootstrap导航条使用方法分享
2016/04/29 Javascript
JavaScript实战之菜单特效
2016/08/16 Javascript
javascript添加前置0(补零)的几种方法
2017/01/05 Javascript
JS实现中国公民身份证号码有效性验证
2017/02/20 Javascript
vue实现全选、反选功能
2020/11/17 Javascript
AngularJS中ng-class用法实例分析
2017/07/06 Javascript
在 vue-cli v3.0 中使用 SCSS/SASS的方法
2018/06/14 Javascript
微信小程序分享海报生成的实现方法
2018/12/10 Javascript
从组件封装看Vue的作用域插槽的实现
2019/02/12 Javascript
vue-router重写push方法,解决相同路径跳转报错问题
2020/08/07 Javascript
在vue中使用image-webpack-loader实例
2020/11/12 Javascript
wxpython 学习笔记 第一天
2009/02/09 Python
python中使用urllib2伪造HTTP报头的2个方法
2014/07/07 Python
Python中使用第三方库xlrd来写入Excel文件示例
2015/04/05 Python
高效测试用例组织算法pairwise之Python实现方法
2017/07/19 Python
Flask框架工厂函数用法实例分析
2019/05/25 Python
Python编程快速上手——strip()函数的正则表达式实现方法分析
2020/02/29 Python
解决python便携版无法直接运行py文件的问题
2020/09/01 Python
CSS3使用多列制作瀑布流
2016/05/10 HTML / CSS
意大利奢侈品综合电商网站:MODES
2019/12/14 全球购物
实现strstr功能,即在父串中寻找子串首次出现的位置
2016/08/05 面试题
医学院四年学习生活的自我评价
2013/11/06 职场文书
2014年机关作风建设工作总结
2014/10/23 职场文书
2015年感恩节活动总结
2015/03/24 职场文书
2015年度培训工作总结范文
2015/04/02 职场文书
小平小道观后感
2015/06/09 职场文书
JS轻量级函数式编程实现XDM二
2022/06/16 Javascript
React如何使用axios请求数据并把数据渲染到组件
2022/08/05 Javascript