自定义递归实现级联组件,可默认展开全部子节点

自定义递归实现级联组件,可默认展开全部子节点

前言

级联组件是各个UI组件库中不可或缺的组件,他们常作为下拉选择使用,可以多选或者单选,但是在最近开发中,这个组件并不能实现产品经理无理的需求(需要默认展开所有子节点,需要支持某一项可多选,其他层不需要选择框。。。等等),既然UI框架用不了,只能自己动手造轮子,能够自定义每个选项的插槽内容。源码git地址:https://gitee.com/fcli/vue-cascade-panel.git

实现效果图如下:

递归组件

对于未知的层级和不确定的树节点,递归大法是最好的选择。

为什么需要递归组件

级联组件的数据结构,其实就是树结构的平铺展开方式,因此如果需要实现一个级联组件,首先使用递归组件是一个最好的选择,配合插槽的使用,能够动态地改变每一层每一个节点的样式和操作方式。

vue如何实现递归组件

需要在组件中使用自身组件,首先需要定义name属性。如果使用的是vue3的setup语法糖,所以需要单独写一个script标签定义name。

<script lang="ts" >
export default {name: 'cascadePanel',
}
</script>

这样在模板中就能通过name使用组件,代码如下:

<template>
<div class="cascade-panel"><cascade-panel></cascade-panel>
</div>
</template>

递归级联组件实现

模板

通过propsIndex判断当前属于哪一层,并通过slot插槽方便上层自定义内容。

<div class="cascade-panel"><div class="menu-item" :class="['level_' + propsIndex]"><div class="slot-item" v-for="(item, index) in datalist" :key="index" @click="change(index)":class="[Number(index) == childActiveId ? 'active' : '']"><slot name="slotScope" :data="item"></slot></div></div><div class="menu-item" :class="['out_level_' + (propsIndex + 1)]"v-if="datalist[childActiveId] && datalist[childActiveId].children"><cascade-panel ref="cascadeRef" :datalist="datalist[childActiveId].children" :propsIndex="propsIndex + 1"v-on:patch="onPatch"><template #slotScope="slotProps"><slot name="slotScope" :data="slotProps.data"></slot></template></cascade-panel></div>
</div>

注意:在内层的插槽定义时data需要使用slotProps.data,不然如果使用slotScope会导致数据嵌套,会有很多层的data

<template #slotScope="slotProps"><slot name="slotScope" :data="slotProps.data"></slot>
</template>
其余主要代码

1、为了让每一层点击的时候都能让下面的几层展开并选中第一个,所以需要在初始化时将childActiveId的值置为0,并循环调用子组件,让所有的子节点都能保持第一个选中状态。

2、通过patch方法,记录当前点击的节点的路径,有需要的小伙伴可自定义修改

需要抛出对应方法,父组件才能调用defineExpose({init})

<script lang="ts" >
export default {name: 'cascadePanel',
}
</script>
<script lang="ts" setup>
import { ref, defineProps } from 'vue';
const props = defineProps({datalist: { default: [], type: Array<any> },propsIndex: {default: 1,type: Number}
});
const emit = defineEmits(['patch'])
const childActiveId = ref(0);
const cascadeRef = ref<any>(null);
const init = () => {childActiveId.value = 0;cascadeRef.value && cascadeRef.value.init();
};
const change = (index: number) => {init();//点击之后下一个组件显示,activeId初始化0childActiveId.value = indexif (!props.datalist[childActiveId.value].children) {emit("patch", props.datalist[childActiveId.value].label);}
}
const onPatch = (val: any) => {var checkedVal = props.datalist[childActiveId.value].label + "/" + val;emit("patch", checkedVal);
}
defineExpose({init})</script>
<style>
.cascade-panel {display: flex;
}
</style>

使用组件

在app.vue 中调用该组件,传入树节点值,并自定义插槽内容。示例中适当实现了一些多选方案。代码如下:

<template><div class="content"><VueCascadePanel :datalist="dataList"><template #slotScope="slotProps"><div class="item">{{ slotProps.data.label }}<input type="checkbox" @change="(e) => changeSelect(e, slotProps.data)" v-model="slotProps.data.isChecked" :checked="modelNode(slotProps.data)" /></div></template></VueCascadePanel></div>
</template><script setup lang="ts">
import VueCascadePanel from './plugin/index.vue';
import { ref } from 'vue';
components: {VueCascadePanel
}const changeSelect = (e: any, data: any) => {const isChecked = e.target._modelValue;getData(isChecked, data)
}
const getData = (isChecked: Boolean, data: any) => {//如果选中,递归修改子节点的选中状态if (data.children?.length > 0) {data.isChecked = isChecked;data.children.forEach((item: any) => {getData(isChecked, item);})} else {data.isChecked = isChecked;}console.log(data)
}const modelNode = (node: any) => {checkedNode.value[node.value] = node;return false;
}const checkedNode = ref<any>({});
const dataList = ref<any>([{value: 'zhinan',label: '指南',children: [{value: 'shejiyuanze',label: '设计原则',isChecked: false,children: [{value: 'yizhi',label: '一致',isChecked: false,}, {value: 'fankui',label: '反馈',isChecked: false,}, {value: 'xiaolv',label: '效率',isChecked: false,}, {value: 'kekong',label: '可控',isChecked: false,}]}, {value: 'daohang',label: '导航',isChecked: false,children: [{value: 'cexiangdaohang',label: '侧向导航',isChecked: false,}, {value: 'dingbudaohang',label: '顶部导航',isChecked: false,}]}]
}, {value: 'zujian',label: '组件',children: [{value: 'basic',label: 'Basic',isChecked: false,children: [{value: 'layout',label: 'Layout 布局',isChecked: false,}, {value: 'color',label: 'Color 色彩',isChecked: false,}, {value: 'typography',label: 'Typography 字体',isChecked: false,}, {value: 'icon',label: 'Icon 图标',isChecked: false,}, {value: 'button',label: 'Button 按钮',isChecked: false,}]}, {value: 'form',label: 'Form',isChecked: false,children: [{value: 'radio',label: 'Radio 单选框',isChecked: false,}, {value: 'checkbox',label: 'Checkbox 多选框',isChecked: false,}, {value: 'input',label: 'Input 输入框',isChecked: false,}, {value: 'input-number',label: 'InputNumber 计数器',isChecked: false,}, {value: 'select',label: 'Select 选择器',isChecked: false,}, {value: 'cascader',label: 'Cascader 级联选择器',isChecked: false,}, {value: 'switch',label: 'Switch 开关',isChecked: false,}, {value: 'slider',label: 'Slider 滑块',isChecked: false,}, {value: 'time-picker',label: 'TimePicker 时间选择器',isChecked: false,}, {value: 'date-picker',label: 'DatePicker 日期选择器',isChecked: false,}, {value: 'datetime-picker',label: 'DateTimePicker 日期时间选择器',isChecked: false,}, {value: 'upload',label: 'Upload 上传',isChecked: false,}, {value: 'rate',label: 'Rate 评分',isChecked: false,}, {value: 'form',label: 'Form 表单',isChecked: false,}]}, {value: 'data',label: 'Data',isChecked: false,children: [{value: 'table',label: 'Table 表格',isChecked: false,}, {value: 'tag',label: 'Tag 标签',isChecked: false,}, {value: 'progress',label: 'Progress 进度条',isChecked: false,}, {value: 'tree',label: 'Tree 树形控件',isChecked: false,}, {value: 'pagination',label: 'Pagination 分页',isChecked: false,}, {value: 'badge',label: 'Badge 标记',isChecked: false,}]}, {value: 'notice',label: 'Notice',isChecked: false,children: [{value: 'alert',label: 'Alert 警告',isChecked: false,}, {value: 'loading',label: 'Loading 加载',isChecked: false,}, {value: 'message',label: 'Message 消息提示',isChecked: false,}, {value: 'message-box',label: 'MessageBox 弹框',isChecked: false,}, {value: 'notification',label: 'Notification 通知',isChecked: false,}]}, {value: 'navigation',label: 'Navigation',isChecked: false,children: [{value: 'menu',label: 'NavMenu 导航菜单',isChecked: false,}, {value: 'tabs',label: 'Tabs 标签页',isChecked: false,}, {value: 'breadcrumb',label: 'Breadcrumb 面包屑',isChecked: false,}, {value: 'dropdown',label: 'Dropdown 下拉菜单',isChecked: false,}, {value: 'steps',label: 'Steps 步骤条',isChecked: false,}]}, {value: 'others',label: 'Others',isChecked: false,children: [{value: 'dialog',label: 'Dialog 对话框',isChecked: false,}, {value: 'tooltip',label: 'Tooltip 文字提示',isChecked: false,}, {value: 'popover',label: 'Popover 弹出框',isChecked: false,}, {value: 'card',label: 'Card 卡片',isChecked: false,}, {value: 'carousel',label: 'Carousel 走马灯',isChecked: false,}, {value: 'collapse',label: 'Collapse 折叠面板',isChecked: false,}]}]
}, {value: 'ziyuan',label: '资源',isChecked: false,children: [{value: 'axure',label: 'Axure Components',isChecked: false,}, {value: 'sketch',label: 'Sketch Templates',isChecked: false,}, {value: 'jiaohu',label: '组件交互文档',isChecked: false,}]
}]);
</script><style>
.cascade-panel {background: #f6f9f9;
}.menu-item .active {background: #d9e4fa;
}.menu-item .item {line-height: 32px;width: 200px;cursor: pointer;
}
</style>

总结

本文主要实现了级联组件的基本思路,保留了更多自定义实现,如果需要实现复杂无理的需求可以参考使用,如果只是简单的选择,推荐使用UI框架里的组件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/174589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【云备份】配置加载文件模块

文章目录 配置信息设计配置文件加载cloud.conf配置文件单例模式的使用ReadConfigFile —— 读取配置文件GetInstance —— 创建对象其他函数的实现 具体实现cloud.confconfig.hpp 配置信息设计 使用文件配置加载一些程序运行的关键信息 可以让程序的运行更加灵活 配置信息&am…

C++ 常见异常

关于C异常&#xff08;包括但不限于编译器异常&#xff09;先开个头&#xff0c;有空都记下来吧&#xff1a; 1&#xff1a;_DllMain12 已经在 MSVCRTD.lib(dllmain.obj) 中定义 有效的解决办法&#xff1a; Debug版本&#xff1a; 项目-属性-链接器-输入&#xff1a;忽略特…

爬取极简壁纸

js反编译的代码需要解密之类的&#xff0c;直接给我干蒙圈了&#xff0c;借助selenium可以直接获取到调式工具中的源码&#xff0c;可以获取渲染后的链接&#xff0c;然后将链接交给下载函数&#xff08;使用异步提高效率&#xff09;即可。 后续学习完js反编译的话&#xff0…

matlab导入excel数据两种常见的方法

在MATLAB中导入Excel数据&#xff0c;你可以使用几种不同的方法。下面是两种常见的方法&#xff1a; 方法一&#xff1a;使用readtable函数 readtable函数允许你导入Excel文件中的数据&#xff0c;并将其存储为表格。 % 指定文件路径 filename C:\your\path\to\file.xlsx;%…

羊大师:不同时段喝羊奶,效果会有何不同?

羊大师&#xff1a;不同时段喝羊奶&#xff0c;效果会有何不同&#xff1f; 羊奶是一种营养丰富、口感香浓的健康饮品&#xff0c;被广大消费者所喜爱。然而&#xff0c;你是否知道&#xff0c;不同的喝奶时间对身体的影响也是不同的呢&#xff1f;在不同时段喝羊奶&#xff0…

【无头双向链表和链表练习题2】

文章目录 以给定值x为基准将链表分割成两部分&#xff0c;所有小于x的结点排在大于或等于x的结点之前输入两个链表&#xff0c;找出它们的第一个公共结点。给定一个链表&#xff0c;判断链表中是否有环无头双向链表的模拟实现ArrayList&#xff08;顺序表&#xff09;和LinkedL…

矢量图片转换软件Vector Magic mac中文版功能特色

Vector Magic mac是一款图片转换矢量图&#xff0c;该软件使用世界上最好的全彩色自动描摹器&#xff0c;快速准备好您的作品进行打印、绣花、剪裁等操作。 Vector Magic mac功能特色 只需上传即可在线自动将 JPG、PNG、BMP 和 GIF 位图图像转换为真正的 SVG、Eps 和 PDF 矢量…

编程中的解密之路:挑战、创新与技术难题的探索

目录 引言 编程的重要性 编程中常见的技术难题 1. Bug追踪&#xff1a;寻找隐藏的恶魔 2. 性能优化&#xff1a;调校引擎的精准之道 3. 跨平台兼容性&#xff1a;寻找最佳的沟通方式 解决技术难题的方法 1. 使用调试工具和日志 2. 采用性能分析工具 3. 采用跨平台框架…

避免手机无节制使用

手机使用情况分析 使用时间 我挑选了11月份某一周的统计数据&#xff0c;可以看到&#xff0c;我的日均手机手机时间达到了惊人的8个小时&#xff0c;每周总共余约57小时。 按照使用软件的类型来分类&#xff0c;其中约%50用于娱乐&#xff0c;主要使用软件为&#xff1a;哔哩…

Django总结

文章目录 一、Web应用Web应用程序的优点Web应用程序的缺点应用程序有两种模式C/S、B/S C/S 客户端/服务端局域网连接其他电脑的MySQL数据库1.先用其他电脑再cmd命令行ping本机ip2.开放MySQL的访问 B/S 浏览器/服务端基于socket编写一个Web应用 二、Http协议1.http协议是什么2.h…

【蓝桥杯备考】第十二届蓝桥杯省赛Java B组真题 编程题

第十二届蓝桥杯省赛Java B组真题 编程题 1. 杨辉三角问题描述 2. 时间显示问题描述 3. 双向排序问题描述 4. 括号序列问题描述分析 5.砝码称重分析 1. 杨辉三角 问题描述 著名的杨辉三角形&#xff0c;按从上到下、从左到右的顺序把所有数排成一列&#xff0c;可以得到如下数…

【上海大学数字逻辑实验报告】一、基本门电路

一、 实验目的 熟悉TTL中、小规模集成电路的外形、管脚和使用方法&#xff1b;了解和掌握基本逻辑门电路的输入与输出之间的逻辑关系及使用规则。 二、 实验原理 实现基本逻辑运算和常用逻辑运算的单元电路称为逻辑门电路。门电路通常用高电平VH表示逻辑值“1”&#xff0c;…

为啥网络安全那么缺人,但很多人却找不到工作?

文章目录 一、学校的偏向于学术二、学的东西太基础三、不上班行不行 为什么网络安全的人才缺口那么大&#xff0c;但是大学毕业能找到网安工作的人却很少&#xff0c;就连招聘都没有其他岗位多&#xff1f; 明明央视都说了网络安全的人才缺口还有300多万&#xff0c;现在找不到…

Java远程连接本地开源分布式搜索引擎ElasticSearch

文章目录 前言1. Windows 安装 Cpolar2. 创建Elasticsearch公网连接地址3. 远程连接Elasticsearch4. 设置固定二级子域名 前言 简单几步,结合Cpolar内网穿透工具实现Java远程连接操作本地Elasticsearch。 什么是elasticsearch&#xff1f;一个开源的分布式搜索引擎&#xff0…

Redux在React中的使用

Redux在React中的使用 1.构建方式 采用reduxjs/toolkitreact-redux的方式 安装方式 npm install reduxjs/toolkit react-redux2.使用 ①创建目录 创建store文件夹&#xff0c;然后创建index和对应的模块&#xff0c;如上图所示 ②编写counterStore.js 文章以counterStore…

JavaScript解构对象

之前介绍了数组解构&#xff0c;本文来介绍一下对象如何解构&#xff1b; 前言 现在我们有这样的一个数组&#xff1a; const restaurant {name: Classico Italiano,location: Via Angelo Tavanti 23, Firenze, Italy,categories: [Italian, Pizzeria, Vegetarian, Organic…

【论文阅读笔记】清单

我的论文清单 记录即将阅读的论文清单&#xff0c;持续更新。 未读论文 以下是我计划阅读但尚未开始的论文列表&#xff1a; 编号方向论文标题作者发表时间发表会议/期刊计划阅读日期code1NerfNeRFMeshing: Distilling Neural Radiance Fields into Geometrically-Accurate…

safari浏览器,直接安装ipa文件

蒲公英二维码方法 个人开发者账号发布证书AD-hoc 描述文件蒲公英上传链接通过苹果safari 浏览器下载IPA包 浏览器下载方法 前置条件 1.下载 ipa 包的设备的 uuid 已加入 苹果测试设备列表如何添加到测试列表 2.web 服务, 文件服务. 3.需要AD-hoc 描述文件 添加链接描述 1.创…

【shell】正则表达式和文本三剑客之grep和awk

目录 一、正则表达式 1.1用法 1.2表示字符匹配 1.3表示次数 1.4表示位置锚定 1.5表示分组或其他 1.6扩展正则表达式 二、grep命令 三、awk命令 3.1awk与vim的区别 3.2awk的语法 3.3基础用法 test1.提取磁盘的分区利用率 test2.提取用户名和uid号 test3.提取ip地址…

探究Kafka原理-5.Kafka设计原理和生产者原理解析

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44…