vue递归组件实现无限极分类菜单/无限极树状图,点击其中一项菜单关闭其它所有菜单项,vue递归组件通过数据定位当前组件层级及定位哪一条数据

先看效果,测试案例,随便加了个css动画:
在这里插入图片描述
不知道使用 vue 递归组件注意事项的自行查看官方文档哈 【查看

比较简单的一个 demo 仅供参考,其它复杂功能的话,能传值,能定位到具体数据了,什么功能做不了,是不是???

准备数据 store.js:

// store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        list: [ // 数据库查出来的数据是这个
            {
                id: 1,
                name: '一级1',
                pid: 0,
                level: 1
            },
            {
                id: 2,
                name: '一级2',
                pid: 0,
                level: 1
            },
            {
                id: 3,
                name: '一级3',
                pid: 0,
                level: 1
            },
            {
                id: 4,
                name: '二级1-1',
                pid: 1,
                level: 2
            },
            {
                id: 5,
                name: '二级1-2',
                pid: 1,
                level: 2
            },
            {
                id: 6,
                name: '二级1-3',
                pid: 1,
                level: 2
            },
            {
                id: 7,
                name: '二级2-1',
                pid: 2,
                level: 2
            },
            {
                id: 8,
                name: '二级2-2',
                pid: 2,
                level: 2
            },
            {
                id: 9,
                name: '二级2-3',
                pid: 2,
                level: 2
            },
            {
                id: 10,
                name: '二级2-4',
                pid: 2,
                level: 2
            },
            {
                id: 11,
                name: '二级3-1',
                pid: 3,
                level: 2
            },
            {
                id: 12,
                name: '二级3-2',
                pid: 3,
                level: 2
            },
            {
                id: 13,
                name: '三级1-1-1',
                pid: 4,
                level: 3
            },
            {
                id: 14,
                name: '三级1-1-2',
                pid: 4,
                level: 3
            },
            {
                id: 15,
                name: '三级1-1-3',
                pid: 4,
                level: 3
            },
            {
                id: 16,
                name: '三级1-2-1',
                pid: 5,
                level: 3
            },
            {
                id: 17,
                name: '三级1-2-2',
                pid: 5,
                level: 3
            },
            {
                id: 18,
                name: '三级2-1-1',
                pid: 7,
                level: 3
            },
            {
                id: 19,
                name: '三级2-1-2',
                pid: 7,
                level: 3
            },
            {
                id: 20,
                name: '三级3-2-1',
                pid: 12,
                level: 3
            },
            {
                id: 21,
                name: '四级1-2-1-1',
                pid: 16,
                level: 4
            },
            {
                id: 22,
                name: '四级1-2-1-2',
                pid: 16,
                level: 4
            },
            {
                id: 22,
                name: '四级3-2-1-1',
                pid: 20,
                level: 4
            }
        ]
    },
    mutations: {},
    getters: {
        menus: (state) => {
            let menu = menusHandler(state.list) // 对数据库查出来的数据进行整合
            return menu
        }
    }
})

function menusHandler(list, menu = [], pid = 0) {
    if (menu.length <= 0) { // 如果 menu 是空的,先找顶级目录
        let tmp = []
        list.forEach((item, index) => {
            if (item.pid == pid) {
                item.flag = true
                item.open = false
                item.pids = '' + pid
                tmp.push(item)
            }
        })
        if (tmp.length > 0) {
            menu = menusHandler(list, tmp)
        }
    } else { // menu 不为空,说明不是顶级的,需查找子级
        menu.forEach(el => {
            let tmp = []
            list.forEach(item => {
                if (el.id == item.pid) {
                    item.flag = false
                    item.open = false
                    item.pids = el.pids + '-' + item.pid
                    tmp.push(item)
                }
            })
            if (tmp.length > 0) {
                el.children = tmp
                menusHandler(list, tmp)
            } else {
                el.children = []
            }
        })
    }
    return menu
}

上方 getters 里边 menus 生成整合后的数据格式如下图所示:
在这里插入图片描述
准备递归组件 component/recursion.vue:

<template>
    <div class="recursion">
        <div class="list-item" v-for="(item, index) in list" :key="index">
            <div
                class="item-name"
                @click="
                    triggerMenu({
                        id: item.id,
                        pid: item.pid,
                        pids: item.pids,
                        level: item.level,
                    })
                "
            >
                <span class="item-name-icon" v-if="item.children.length">{{
                    item.open ? "-" : "+"
                }}</span>
                <span class="item-name-icon" v-else>-</span>
                <span class="item-name-txt">{{ item.name }}</span>
            </div>
            <transition name="show-hide">
                <div v-show="item.open" class="children-item" :id="item.id">
                    <recursion
                        :list="item.children"
                        @triggerMenu="triggerMenu"
                    ></recursion>
                </div>
            </transition>
        </div>
    </div>
</template>

<script>
export default {
    name: "recursion",
    props: {
        list: Array,
    },
    methods: {
        triggerMenu({ id, pid, pids, level }) {
            this.$emit("triggerMenu", { id, level, pids, pid });
        },
    },
};
</script>
<style lang='scss'>
.recursion {
    text-align: left;
    .list-item {
        box-sizing: border-box;
        padding-top: 6px;
        padding-left: 40px;
        .item-name {
            // width:300px;
            .item-name-icon {
                display: inline-block;
                vertical-align: middle;
                width: 28px;
                height: 28px;
                line-height: 28px;
                text-align: center;
            }
            .item-name-txt {
                display: inline-block;
                vertical-align: middle;
            }
        }
    }
}
.show-hide-enter-active {
    animation: show-hide 0.5s;
}
.show-hide-leave-active {
    animation: show-hide 0.5s reverse;
}
@keyframes show-hide {
    0% {
        transform: scale(0);
    }
    100% {
        transform: scale(1);
    }
}
</style>

调用 pages/index.vue:

<template>
    <div class="home">
        <div class="menu">
            <recursion :list="list" @triggerMenu="triggerMenu"></recursion>
        </div>
    </div>
</template>

<script>
import Recursion from "./../components/Recursion";
export default {
    name: "index",
    components: { Recursion },
    data() {
        return {
            list: [],
        };
    },
    mounted() {
        setTimeout(() => { // 异步模拟接口请求过来数据,这个随意啦,写 vuex 里啥的都没问题,自行修改吧
            this.list = this.$store.getters.menus;
        }, 1000);
    },
    methods: {
        triggerMenu({ id, pid, pids, level }) {
            let pidsArr = ("" + pids).split("-");
            let menus = JSON.parse(JSON.stringify(this.list));
            function showHideMenus(menus, id) {
                menus.forEach((item) => {
                    if (pidsArr.includes("" + item.id)) { // 这里定位当前菜单直属所有上级
                        item.open = true;
                    } else if (item.id == id) { // 这里定位点击的当前菜单
                        item.open = !item.open;
                    } else { // 这里定位当前菜单以外的其它菜单
                        item.open = false;
                    }
                    if (item.children && item.children.length > 0) {
                        showHideMenus(item.children, id);
                    }
                });
            }
            showHideMenus(menus, id);
            this.list = menus;
        },
    },
};
</script>
<style lang='scss'>
.menu {
    width: 400px;
    overflow: auto;
}
</style>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
更新历史3.0: 环境:jdk1.5 tomcat5.5.数据库用oracle.如果不用oracle的话.可能菜单表的查询出不来.我的菜单表的查询允许选择上级菜单查询该菜单所对应的所有下级菜单.所以用了递归查询. criteria.add(Restrictions.sqlRestriction("MENUITEM_ID in(select a.MENUITEM_ID from Wuxin_MENUITEM a connect by prior a.MENUITEM_ID = a.PARENT_ID"+ " start with a.MENUITEM_ID = '"+parentId+"')" )); mysql和sqlserver不知道有没有start with这个sql. jar包:项目中除了使用了struts2,hibernate3.0和spring1.8以外(用spring2.0的包也可以.不能低于1.8的包.)还是用了junit,ajax,第三方的table组件.等等.所以需要下载相对应的包. 为了上传jar.我专门申请了一个网盘.所有下载地址在下载下来的这个rar包里面都有详细的介绍和说明. 说一下这个rar里面带的东西.除了源码外带了几篇文档.分别是关于项目中所使用的dwr的配置.table组件的配置说明文档.junit单元测试说明文档.还有我写这个例子时应该注意的一些东西.外加一些关于struts2和hibernate的技巧心得整理. 说一下这次3.0更新的内容.可能大家在我的博客里面已经看到了相关的日志.我懒.下面就把那个日志抽出来当说明了啊.有兴趣的就下载下来瞅瞅.偶也是菜鸟的.写的不好不要骂街啊..在此感谢各位网友的期待和支持. 这几天我终于闲下来了.也有时间开始写struts2的第三个框架版本了.主要是针对写了第二个版本之后的一些问题做一些回答才做得第三个版本.中间加一些小技巧之类的.不过我觉得还是值得一些关注的朋友期待的. 如果没有意外.这个版本应该是一个定型的版本了.在这段期间.有很多朋友问的问题大部分其实都已经不是struts2的范围了.有些都是hibernate和spring的.介于前两个版本都是单表.对hibernate的引用还是比较少的.这次索性写个多对多关系好了.打算写个权限系统好了.我就使用权限5张表.用户表,权限表.角色表.用户角色表和角色菜单表.(麻雀虽小...五脏俱全了啊...)当然这个写起来就费劲一些了.... 为了能够更好的使用各方面的技术.所以这次打算弄个大锅(弄个大锅也很累的.不过大家可能到时候配这个框架也就比较麻烦点了...不过我觉得还是能多学一下总是好的.) 说一下大锅的内容吧.自己写了个分页组件.(不是太好看...).现在ajax都已经不是什么新鲜东东了..我在里面配的是dwr..(这个简单些..其他的我看着晕...).没有自己写页面输出.我使用的table组件是:eXtremeComponents.自我感觉这个组件比较好.所以把这个组件配入进来了.随着这篇文章的发布.我会陆续在博客中更新相关针对与当前项目模块的关于struts2的一些知识点.当作大家一起进步了... 也希望各位高人多多指点啊... 这个版本起名为Struts2Test3.0.以后的日志相关内容就为关于Struts2Test3.0例子的相关内容.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值