广告
返回顶部
首页 > 资讯 > 精选 >怎么使用vue递归实现树形组件
  • 676
分享到

怎么使用vue递归实现树形组件

2023-07-02 18:07:34 676人浏览 八月长安
摘要

这篇文章主要介绍“怎么使用Vue递归实现树形组件”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用vue递归实现树形组件”文章能帮助大家解决问题。1. 先来看一下效果:2. 代码部分 (myTr

这篇文章主要介绍“怎么使用Vue递归实现树形组件”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用vue递归实现树形组件”文章能帮助大家解决问题。

1. 先来看一下效果:

怎么使用vue递归实现树形组件

2. 代码部分 (myTree.vue)

图片可以自己引一下自己的图片,或者使用iconfont的CSS引入。

<template>    <div class="tree">        <ul class="ul">            <li v-for="(item,index) of treeMenu" :key="index">                <div class="jiantou" @click="changeStatus(index)">                    <img src="../../assets/right.png" v-if="!scopesDefault[index]===true && item.children">                    <img src="../../assets/down.png" v-if="scopesDefault[index]===true && item.children ">                </div>                <input type="checkbox" @click="checkBox(item)" v-model="item.check">                <span @click="changeStatus(index)">{{item.label}}</span>                <div class="subtree">                    <tree-menu :treeMenu='item.children' v-if="scopesDefault[index]" @selectnode = "selectnode"></tree-menu>                </div>            </li>          </ul>     </div> </template><script>    export default{    name:'treeMenu',     props:{        treeMenu:{            type:Array,            default:[]        },    },    data(){        return{            scopesDefault: [],            scopes: [],             node:[],            flatTreeMenu:[],            check:'',        }    },    methods:{        //展开        scope() {            this.treeMenu.forEach((item, index) => {                this.scopesDefault[index] = false                if ('children' in item) {                    this.scopes[index] = true                    //console.log(item, index)                } else {                    this.scopes[index] = false                }            })        },        changeStatus(index) {            if (this.scopesDefault[index] == true) {                this.$set(this.scopesDefault, index, false)            } else {                this.$set(this.scopesDefault, index, this.scopes[index])            }        },        //nodelist 深度优先递归        checkBox(node,nodelist=[]){            //console.log("start:",node,nodelist)            if(node!==null){                nodelist.push(node);                if(node.children){                    let children=node.children;                    for(let i=0;i<children.length;i++){                        this.checkBox(children[i],nodelist)//递归调用                        children[i].check = nodelist[0].check==false?true:false;//选中父节点,子节点全选,取消,子节点取消                    }                }            }            this.node=node;            this.check=node.check        },        selectnode(node){            this.$emit("selectnode",node);        }    },    watch:{         node:{            handler(val){                this.selectnode(val);            },            immediate: true        },        check:{            handler(val){                this.selectnode(this.node);            },            immediate: true        }    },    mounted(){        this.scope();     }}</script>
<style lang = "scss" scoped>.tree{    .ul{        margin: 5px 0 5px 0;        >li{            .jiantou{                display: inline-block;                width: 15px;                >img{                position: relative;                top: 2.0px;                left: 4px;                }            }            .subtree{                margin-left: 20px;                margin-top: 8px;                margin-bottom: 8px;            }        }    }}input[type=checkbox]{    visibility: hidden;    cursor: pointer;    position: relative;    width: 15px;    height: 15px;    font-size: 14px;    border: 1px solid #dcdfe6;    background-color: #fff !important;    &::after{        position: absolute;        top: 0;        background-color: #fff;        border: 1px solid #DDD;        color: #000;        width: 15px;        height: 15px;        display: inline-block;        visibility: visible;        padding-left: 0px;        text-align: center;        content: ' ';        border-radius: 3px;        transition: all linear .1s;    }    &:checked::after{        content: "\2713";        font-size: 12px;        background-color: #409eff;        border: 1px solid #409eff;        transition: all linear .1s;        color: #fff;        font-weight: bold;    }}.check{    &:checked::after{        content: "--" !important;    }}</style>

讲解:

调用组件:

我这用来一个global.js来控制组件的使用(这个js附在文章末尾了),在component文件夹中建立一个myTree文件夹,里面放同名vue文件(myTree.vue),这样无论在哪里调用这个组件,都可以直接使用<my-tree></my-tree>的方式去调用。

组件的方法:

scope():会生成一个数组,里面有根节点是否有子节点,如本代码里设定的数据,会有scopes=[true,true,true]这样的结果。
changeStatus():每点击标题或者箭头,如果当前下标的节点有没有子节点,再将结果动态赋值给scopesDefault[index],将这个值放于dom上控制开关,递归组件。
checkBox():在组件内部实现了点击全选、点击取消全选的功能,递归调用当前方法,将子元素的状态随父元素一起变化。
selectnode():将当前点击的node的节点内容上传到父组件。

监听:

同时监听:不同节点的切换、同一个节点的是否选中的切换,监听得到的结果都传到父组件中。

组件递归:调用时与父组件相同

3. 使用组件(useMyTree.vue)

<template>    <div class = "loginModuel">        <my-tree :treeMenu='tree' @selectnode="selectnode"></my-tree>    </div></template><script>export default{    data(){        return{            msg:"这是登录页面",            tree:[                  {                    id:1,                    label:"1级目录1",                    check:false,                    children:[                        {                            id:"1-1",                            pid:1,                            label:"1.1目录",                            check:false                        },                        {                            id:"1-2",                            pid:1,                            label:"1.2目录",                            check:false                        },                        {                            id:"1-3",                            pid:1,                            label:"1.3目录",                            check:false                        },                    ]                },                {                  id:2,                  label:"1级目录2",                  check:false,                  children:[                      {                          id:"2-1",                          label:"2.1目录",                          check:false,                          pid:2,                          children:[                            {                                id:"2-1-1",                                pid:'2-1',                                label:"2.1.1目录",                                check:false,                                children:[                                    {                                        id:"2-1-1-1",                                        pid:'2-1-1',                                        label:"2.1.1.1目录",                                        check:false,                                        children:[                                            {                                                id:"2-1-1-1-1",                                                pid:'2-1-1-1',                                                label:"2.1.1.1.1目录",                                                check:false,                                            },                                            {                                                id:"2-1-1-1-2",                                                pid:'2-1-1-1',                                                label:"2.1.1.1.2目录",                                                check:false,                                            },                                        ]                                    },                                ]                            },                            {                                id:"2-1-2",                                pid:'2-1',                                label:"2.1.2目录",                                check:false,                            },                            {                                id:"2-1-3",                                pid:'2-1',                                label:"2.1.3目录",                                check:false,                            },                        ]                      },                      {                          id:"2-2",                          pid:2,                          label:"2.2目录",                          check:false                      }                  ]              },//在此继续添加目录              {                id:3,                label:"1级目录3",                check:false,                children:[                    {                        id:"3-1",                        pid:3,                        label:"3.1目录",                        check:false,                        children:[                            {                                id:"3-1-1",                                pid:"3-1",                                label:"3.1.1目录",                                check:false,                                children:[                                    {                                        id:"3-1-1-1",                                        pid:"3-1-1",                                        label:"3.1.1.1目录",                                        check:false,                                        children:[                                            {                                                id:"3-1-1-1-1",                                                pid:"3-1-1-1",                                                label:"3.1.1.1.1目录",                                                check:false                                            },                                        ]                                    },                                ]                            },                        ]                    }                ]            },            ],            plist:[],//此级以上所有父节点列表            flatTree:[],//tree的平行数据            node:'',//当前点击的node,        }    },    methods:{        //将tree树形数据转换为平行数据        transfORMData(tree){            tree.forEach(item=>{                this.flatTree.push(item);                item.children && item.children.length>0 ? this.transformData(item.children) : ""            })        },        //子组件传递过来的点击的node的值        selectnode(node){            this.node=node;            this.flatTree=[];            this.transformData(this.tree);            if(node.check==false){//这个节点已经被选中,正在点击取消选中                this.plist=[];//每次点击一个新的节点都将原来plist的内容清空                this.getParentnode(this.flatTree,node.pid)            }else{//正在选中                this.childAllToParent(node,this.flatTree,1);            }        },        //子节点取消选中,拿到此子节点所有的父节点plist        getParentnode(tree,pid){            //this.plist=[]            if(pid!==null){                tree.forEach(item=>{                    if(item.id==pid){                        this.plist.push(item)                        this.getParentnode(this.flatTree,item.pid)                    }                })            }             if(!pid){                this.plist.forEach(item=>{                    this.updateParentCheck(this.tree,item)                })            }        },        //将原数据tree对应id的项的check值改为false        updateParentCheck(tree,plistItem){            //console.log("方法updateParentCheck接收的plistItem参数:",plistItem)            tree.forEach(item=>{                if(item.id==plistItem.id){                    item.check=false;                }                if(item.id!==plistItem.id && item.children){                    this.updateParentCheck(item.children,plistItem)                }            })        },        //子节点全部选中后父节点选中        childAllToParent(node,flatTree,j){            let fatherNode='';            let brotherNode=[];            this.flatTree.forEach(item=>{                if(node.pid && node.pid==item.id){                    fatherNode=item;//找到了父节点--用于改变check的值                }            })            //判断该结点所有的兄弟节点是否全部选中            flatTree.forEach(item=>{                if(item.pid && node.pid && item.pid==node.pid){                    brotherNode.push(item)//找到所有的兄弟节点                }            })            //i为被选中的兄弟节点的个数            let i=0;            this.flatTree.forEach(item=>{                if(node.pid==item.pid && item.check==true){                    i=i+1;                }            })            //修改父节点的选中值            if(i==brotherNode.length && fatherNode){                fatherNode.check=true            }            // console.log(`第j次递归 j=${j}`)            // console.log(`选中的bro=${i},brother的个数:${brotherNode.length}`)            // console.log("父节点:",fatherNode,"兄弟节点",brotherNode)            if(fatherNode.pid!==undefined){                j=j+1;                this.childAllToParent(fatherNode,this.flatTree,j)            }        }    },    mounted(){        this.transformData(this.tree);//数据初始化:将tree树形数据转换为平行数据        //console.log(this.flatTree)    }}</script>
<style lang = "scss" scoped>.loginModuel{    margin-left: 400px;    margin-top: 100px;    .tree{        .ul{            >li{                margin: 5px 0 5px 0;                >img{                    position: relative;                    top: 2.4px;                    left: 4px;                }            }            .ul2{                >li{                    position: relative;                    left: 20px;                    margin: 5px 0 5px 0;                    >img{                        //transition: all ease-in-out 1s;                        position: relative;                        top: 2.4px;                        left: 4px;                    }                }            }        }    }}input[type=checkbox]{    cursor: pointer;    position: relative;    width: 15px;    height: 15px;    font-size: 14px;    border: 1px solid #dcdfe6;    background-color: #fff !important;    &::after{        position: absolute;        top: 0;        background-color: #fff;        border: 1px solid #ddd;        color: #000;        width: 15px;        height: 15px;        display: inline-block;        visibility: visible;        padding-left: 0px;        text-align: center;        content: ' ';        border-radius: 3px;        transition: all linear .1s;    }    &:checked::after{        content: "✓";        font-size: 12px;        background-color: #409eff;        border: 1px solid #409eff;        transition: all linear .1s;        color: #fff;        font-weight: bold;    }}</style>

子组件主要是实现全选和取消全选。由于递归组件的原因,子组件拿不到完整的数据,所以接下来的两个功能:全选后某一个子节点取消选中则父节点取消选中、子节点全选后父节点自觉选中的功能就要在父组件中完成了。

讲解:

设值:

树形数据必须有pid属性,用于向上遍历。

方法:

transformData():将层级数据转为平行数据,避免后期不停的递归调用消耗时间,平级数据使用一般的循环即可完成。
selectnode():由子组件传递过来的方法,大致分为两个方向:选中、取消选中。选中时实现功能一:子节点全选后父节点自觉选中;取消选中实现功能二:全选后某一个子节点取消选中则父节点取消选中。
getParentnode():用于实现功能二。子节点取消选中后,根据pid,将在它上面级别的所有父节点列表拿到,再由方法updateParentCheck()将父节点的check值全部改为false
childAllToParent():用于实现功能一。递归调用该方法,将操作节点的父节点拿到,根据兄弟节点有相同的pid,拿到兄弟节点的个数,如果兄弟节点中被选中的个数等于兄弟节点的个数,则修改父节点的check值为true,直到到了根节点结束递归。

  • 这个组件实现起来不是很难,只要是心细就能很好的完成。

  • 如果后期需要使用某些数据的话,直接挂到data里就可以。

  • 如果有更好的方法或者存在某些疑问,欢迎小伙伴留言!

附: (global.js => 放于component文件夹下)

import Vue from 'vue';function capitalizeFirstLetter(string){    return string.charAt(0).toUpperCase() + string.slice(1);}const requireComponent = require.context(    '.',true,/\.vue$/    //找到components文件夹下以.vue命名的文件)requireComponent.keys().forEach(fileName => {    const componetConfig = requireComponent(fileName);    let a = fileName.lastIndexOf('/');    fileName = '.' + fileName.slice(a);    const componetName = capitalizeFirstLetter(        fileName.replace(/^\.\//,'').replace(/\.\w+$/,'')    )    Vue.component(componetName,componetConfig.default || componetConfig)})
  • 由此其实可以实现很多递归组件,如侧边栏。

  • 下面我放一个自己写的侧边栏的动图,方法比这个树形组件要简单些,毕竟不用考虑复选框的值。感兴趣的小伙伴们可以试着实践一下

怎么使用vue递归实现树形组件

关于“怎么使用vue递归实现树形组件”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: 怎么使用vue递归实现树形组件

本文链接: https://www.lsjlt.com/news/343651.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么使用vue递归实现树形组件
    这篇文章主要介绍“怎么使用vue递归实现树形组件”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用vue递归实现树形组件”文章能帮助大家解决问题。1. 先来看一下效果:2. 代码部分 (myTr...
    99+
    2023-07-02
  • vue递归实现树形组件
    本文实例为大家分享了vue递归实现树形组件的具体代码,供大家参考,具体内容如下 1. 先来看一下效果: 2. 代码部分 (myTree.vue) 图片可以自己引一下自己的图片,或者...
    99+
    2022-11-13
  • 怎么使用Vue递归组件实现树形菜单
    本文小编为大家详细介绍“怎么使用Vue递归组件实现树形菜单”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用Vue递归组件实现树形菜单”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。效果如下图,点击后打开二级...
    99+
    2023-07-04
  • vue递归组件实现树形结构
    本文实例为大家分享了vue递归组件实现树形结构,供大家参考,具体内容如下 一、递归组件 什么是递归组件?简单来说就是在组件中内使用组件本身。函数自己调用自己。很多情况下我们呢刷数据的...
    99+
    2022-11-13
  • vue如何使用递归组件实现一个树形控件
    这篇文章主要介绍“vue如何使用递归组件实现一个树形控件”,在日常操作中,相信很多人在vue如何使用递归组件实现一个树形控件问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue如何使用递归组件实现一个树形控件...
    99+
    2023-07-04
  • vue开发树形结构组件(组件递归)
    本文实例为大家分享了vue开发树形结构组件的具体代码,供大家参考,具体内容如下 需求 一个页面,要显示商品分类,同时每个分类下面还拥有若干子类,子类也可以有子类。 要实现全选单选,子...
    99+
    2022-11-12
  • vue递归组件之如何实现简单树形控件
    这篇文章主要介绍vue递归组件之如何实现简单树形控件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1、递归组件-简单树形控件预览及问题 在编写树形组件时遇到的问题:组件如何...
    99+
    2022-10-19
  • 如何使用Vue递归组件构建树形菜单
    今天小编给大家分享一下如何使用Vue递归组件构建树形菜单的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。在Vue.js中一个递...
    99+
    2023-07-04
  • VUE递归树形怎么实现多级列表
    今天小编给大家分享一下VUE递归树形怎么实现多级列表的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。什么是递归简单来说就是在组...
    99+
    2023-07-02
  • Vue2递归组件如何实现树形菜单
    小编给大家分享一下Vue2递归组件如何实现树形菜单,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!效果如下图,点击后打开二级菜单,...
    99+
    2022-10-19
  • vue怎么实现左侧菜单树形图递归
    这篇文章主要讲解了“vue怎么实现左侧菜单树形图递归”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue怎么实现左侧菜单树形图递归”吧!先说说遇到的坑,由于是子父组件,当时传递使用的是子父组...
    99+
    2023-07-04
  • VUE递归树形实现多级列表
    本文实例为大家分享了VUE递归树形实现多级列表,供大家参考,具体内容如下 什么是递归 简单来说就是在组件中内使用组件本身。 为什么要用递归? 如果出现很多下拉菜单,同级,分级数据,层...
    99+
    2022-11-13
  • vue中怎么实现左侧菜单和树形图递归
    本文小编为大家详细介绍“vue中怎么实现左侧菜单和树形图递归”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue中怎么实现左侧菜单和树形图递归”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。效果图如下所示:先说说...
    99+
    2023-06-20
  • Vue.js中怎么利用递归组件构建树形菜单
    本篇文章给大家分享的是有关Vue.js中怎么利用递归组件构建树形菜单,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。在Vue.js中一个递归组件...
    99+
    2022-10-19
  • Vue下如何用递归组件实现一个可折叠的树形菜单
    这篇文章主要介绍“Vue下如何用递归组件实现一个可折叠的树形菜单”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue下如何用递归组件实现一个可折叠的树形菜单”文章能帮助大家解决问题。在Vue.js中...
    99+
    2023-07-04
  • 怎么使用Vue组件tree实现树形菜单
    本篇内容主要讲解“怎么使用Vue组件tree实现树形菜单”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么使用Vue组件tree实现树形菜单”吧!vue 编写的树形菜单,小巧实用,支持vue1....
    99+
    2023-07-04
  • Vue.js中怎么利用递归组件实现一个可折叠的树形菜单
    本篇文章给大家分享的是有关Vue.js中怎么利用递归组件实现一个可折叠的树形菜单,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。在Vue.js中...
    99+
    2022-10-19
  • sqlserver中怎么实现树形结构递归查询
    本篇文章为大家展示了sqlserver中怎么实现树形结构递归查询,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。公用表表达式(CTE),是一个在查询中定义的临时命名结...
    99+
    2022-10-18
  • vue中如何实现左侧菜单,树形图递归
    这篇文章给大家分享的是有关vue中如何实现左侧菜单,树形图递归的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。效果图如下所示:先说说遇到的坑,由于是子父组件,当时传递使用的是子父组...
    99+
    2022-10-19
  • Java怎么用递归实现树形结构的工具类
    本文小编为大家详细介绍“Java怎么用递归实现树形结构的工具类”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java怎么用递归实现树形结构的工具类”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。需求描述有时候,我...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作