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

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

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

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

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递归组件实战之简单树形控件实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • vuejs使用递归组件实现树形目录的方法

    上篇文章我提到了通讯录的开发,里面的目录使用了vue的递归组件实现的树形目录,这篇文章就来讲讲如何实现树形目录吧! 首先实现效果如下,觉得菜单还是比较nice的是吧: 这边数据调用的是数据库的数据的,需要数据库进行数据的构造,这里涉及到java的构造多叉树的知识,后续我会另外写一篇文章详细讲解,这里讲下前端. 数据可以先构造json使用,这里用到的格式大概如下,以childList来嵌套子菜单: { id:YH, name:银行, pid:0, childList:[{ id:YH******,

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

    在Vue.js中一个递归组件调用的是其本身,如: Vue.component('recursive-component', { template: `<!--Invoking myself!--> <recursive-component></recursive-component> }); 递归组件常用于在blog上显示注释.嵌套的菜单,或者基本上是父和子相同的类型,尽管具体内容不同.例如: 现在给您演示一下如何有效地使用递归组件,我将通过建立一个可扩展/收缩的树形菜

  • Vue.js 递归组件实现树形菜单(实例分享)

    最近看了 Vue.js 的递归组件,实现了一个最基本的树形菜单. 项目结构: main.js 作为入口,很简单: import Vue from 'vue' Vue.config.debug = true import main from './components/main.vue' new Vue({ el: '#app', render: h => h(main) }) 它引入了一个组件 main.vue: <template> <div class="tree-m

  • VUE饿了么树形控件添加增删改功能的示例代码

    本文介绍了VUE饿了么树形控件添加增删改功能的示例代码,分享给大家,具体如下: element-ui树形控件:地址 在原文档中有个案例是有新增和删除功能,但是后来发现其修改的数据并不能直接影响到树形数据,所以采用了 render-content 的API重新写了个组件. 写个开发的步骤,所以文章比较长emmm 大致效果如图: 1.省市API 在网上复制了个省市的list,有两个属性是新增的 isEdit :控制编辑状态 maxexpandId :为现下id的最大值 export default{

  • Vue2递归组件实现树形菜单

    今天看了老长时间递归组件,官方给的教程太简便了,根本看不出到底怎么用.于是自己查网摸索了一下,这儿只把核心思想写出来. 效果如下图,点击后打开二级菜单,再点击后打开三级. //js //引子 //思想:当v-if='false'时,循环时进行的.所以一开始就设置为false. ggg:{ name:'gs', template:` <div> <p @click.stop='show=!show'>我是p标签</p> //这儿show必须要初始值为false,不然就是堆

  • vue elementUI tree树形控件获取父节点ID的实例

    首先找到element-ui.common.js文件 如下 具体看你工程下的node_modules D:\workSpace\vue_manage\node_modules\element-ui\lib\element-ui.common.js 找到getCheckedNodes该方法 细节如下我的该方法在21618行 TreeStore.prototype.getCheckedNodes = function getCheckedNodes() { var leafOnly = argume

  • 用 Vue.js 递归组件实现可折叠的树形菜单(demo)

    在Vue.js中一个递归组件调用的是其本身,如: Vue.component('recursive-component', { template: `<!--Invoking myself!--> <recursive-component></recursive-component>` }); 递归组件常用于在blog上显示注释.嵌套的菜单,或者基本上是父和子相同的类型,尽管具体内容不同.例如: 现在给您演示一下如何有效地使用递归组件,我将通过建立一个可扩展/收缩的树形

  • vue.js学习之递归组件

    递归组件 组件在它的模板内可以递归地调用自己,只有当它有 name 选项时才可以. 在官网这句话就是关键定义组件是一定要有name属性.按照这个思路我们开动吧. 实现最终效果图: 模拟数据格式如下: var data = [{ "id": "1", "data": { "menuName": "项目管理", "menuCode": "", }, "child

  • vue.js element-ui tree树形控件改iview的方法

    element-ui组件的tree树形控件修改源码改为iview组件 实现原理 修改了element-ui源码,把源码里面的tree模块提取出来 然后修改element自带checkbox等组件为iview的checkbox,并且兼容方法 最后修改element样式,改为iview风格,自己也添加了一些样式 新的tree组件可以说是element的逻辑,iview的风格 <template> <div @click.stop="handleClick" v-show=

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

    1.递归组件-简单树形控件预览及问题 在编写树形组件时遇到的问题: 组件如何才能递归调用? 递归组件点击事件如何传递? 2.树形控件基本结构及样式 <template> <ul class="vue-tree"> <li class="tree-item"> <div class="tree-content"><!--节点内容--> <div class="expand-

  • C#实现简单的loading提示控件实例代码

    自己画一个转圈圈的控件 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows

  • Android 底部导航控件实例代码

    一.先给大家展示下最终效果 通过以上可以看到,图一是简单的使用,图二.图三中为结合ViewPager共同使用,而且都可以随ViewPager的滑动渐变色,不同点是图二为选中非选中两张图片,图三的选中非选中是一张图片只是做了颜色变化. 二. 需求 我们希望做可以做成这样的,可以在xml布局中引入控件并绑定数据,在代码中设置监听回调,并且配置使用要非常简单! 三.需求分析 根据我们多年做不明确需求项目的经验,以上需求还算明确.那么我们可以采用在LinearLayout添加子View控件,这个子Vie

  • Android自定义顶部导航栏控件实例代码

    下面一段代码给大家介绍了android 自定义顶部导航栏控件功能,具体代码如下所示: class HeaderBar @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr) { //重写构造方法 在java里面 我们一般是重写三个构造方法//在kotlin中 我们可以使用

  • vue自定义组件实现v-model双向绑定数据的实例代码

    项目中会遇到自定义公共组件供项目调用,正常情况可以使用 props定义参数接收父组件传的参数,然后通过子组件的$emits()方法回传数据给父组件. 类似如下: 父组件 <common-checkbox :checked="goodsSelected" class="left" :height="'16px'" :width="'16px'" @checkChange="checkChange">

  • 安卓自定义流程进度图控件实例代码

    先上效果图: 如图,可实现设置:总流程数.已完进度程数.已完成颜色,各个标题 github地址戳这里 使用方法 1.导入compile 'com.github.pavlospt:circleview:1.3'依赖包(因为用到了CircleView) 2.直接把下面两个文件一个java一个xml,复制粘贴进项目(代码放在了文章最后,暂时还没弄成开源库,有时间直接做成依赖包倒进去) 在xml中写入ProcessImg控件 在java文件中实例化ProcessImg对象 根据需要调用几个方法 1.对象

  • Android实现一个丝滑的自动轮播控件实例代码

    前言 现在很多的 App 都有自动轮播的 banner 界面,用于展示广告图片或者显示当前比较热门的一些活动,除了具备比较酷炫的效果之外,通过轮播的方式来减少对界面的占用,也是很赞的一个设计点.本文主要是总结自动轮播控件的实现过程,以及对这类控件的一些优化的技巧. 一.如何实现 在开始进行我们的代码编程之前,我们先要思考一下,在 Google 提供的官方 Api 里面,有没有类似的控件实现了相似的功能,毕竟官方的控件大都经过了时间的考验,无论是稳定性还是性能方面都是非常不错的,如果我们能够基于官

  • Android实现万能自定义阴影控件实例代码

    目录介绍 01.阴影效果有哪些实现方式 02.实现阴影效果Api 03.设置阴影需要注意哪些 04.常见Shape实现阴影效果 05.自定义阴影效果控件 06.如何使用该阴影控件 07.在recyclerView中使用注意点 01.阴影效果有哪些实现方式 阴影效果有哪些实现方式 第一种:使用CardView,但是不能设置阴影颜色 第二种:采用shape叠加,存在后期UI效果不便优化 第三种:UI切图 第四种:自定义View 否定上面前两种方案原因分析? 第一个方案的CardView渐变色和阴影效

  • 在WPF中动态加载XAML中的控件实例代码

    本文实例讲述了在WPF中动态加载XAML中的控件的方法.分享给大家供大家参考,具体如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using S

  • Android实现滑动选择控件实例代码

    前言 最近做了个滑动选择的小控件,拿出来给大家分享一下,先上图 运行效果 实现步骤 这里分解为3个动作:Down.Move.Up来进行分析,博主文采不好,大家直接看流程图吧!! 代码分析 前置知识 1.这个地方使用的是RecyclerView的代码,使用RecyclerView只能使用LinearLayoutManager,ListView的运行效果稍微要比RecyclerView差一些 //这里使用dispatchTouchEvent,因为onTouchEvent容易被OnTouchListe

随机推荐