vue3+vant 实现树状多选组件
vue3+vant 实现树状多选组件
- 需求描述
- 效果图
- 代码
- 父组件引用
- selectTree组件
- tree组件
- 数据格式
需求描述
移动端需要复刻Pc端如上图的功能组件,但vant无组件可用,所以自己封装一个。
效果图
代码
父组件引用
import TreeSelect from "/selectTree.vue"<treeSelectref="treeSelectRef"v-model:show="showAera":modelValue="modelValue":listData="options":multiple='true'placeholder="请选择"@changeModelValue="changeModelValue"></treeSelect>
selectTree组件
<template><van-popup v-model:show="showPicker" round position="bottom" @click-overlay="onClickOverlay" ><div class="tree-box"><div class="tree-container"><div class="tree-data"><TreeSelectref="treeSelectRef":list="data.list":listObj="data.listObj"@confirm="onConfirm"></TreeSelect></div></div></div><div class="tree-confirm"><van-button type="primary" block @click="handleConfirm">确定</van-button></div></van-popup>
</template><script setup>
import { reactive, watch, ref, nextTick, onMounted } from "vue";
import TreeSelect from "./tree.vue";
import { showLoadingToast, closeToast } from "vant";const emits = defineEmits(["changeModelValue", "update:show", "confirm"]);
const props = defineProps({show: {type: Boolean,default: false,},// 绑定值modelValue: {type: Array,default() {return [];},},listData: {type: Array,default() {return [];},},
});watch(() => props.show,() => {showPicker.value = props.show;initData(props.listData);}
);const showPicker = ref(props.show);
const data = reactive({list: props.listData, // 树数组listObj: {}, // 数组对象selectList: [], // 选中的数据canCheckList: [], // 能够选择的数据集合canCheckListFixed: [], // 固定的能够选择的数据集合
});const treeSelectRef = ref(null);const init = (type) => {data.canCheckList = [];data.canCheckListFixed = [];
};
const initData = (options) => {if (options && options.length) {options[0].first=truedata.list = options;init();data.listObj = setListObj(options);}
};// 将树形数据转为扁平对象
const setListObj = (list) => {let listObj = {};list.forEach((itm) => {if(props.modelValue&&props.modelValue.indexOf(itm.id)!==-1){itm.checked=true}data.canCheckList.push(itm);data.canCheckListFixed.push(itm);listObj[itm.id] = itm;if (itm.children && itm.children.length) {listObj = {...listObj,...setListObj(itm.children),};}});return listObj;
};const onClickOverlay = () => {emits("update:show", false);
};
// 确认
const handleConfirm = () => {emits("changeModelValue", data.selectList);emits("update:show", false);
};const onConfirm = (e) => {const showSelectList = filterData(e);data.selectList = showSelectList.map((itm) => itm.id);
};// 过滤数据
const filterData = (selectList) => {// 过滤出展示中,且打勾的数据const showSelectList = selectList.filter((itm) => {return !itm.isHide && !itm.isShowChildren;});return showSelectList;
};const sendWordShow = ref(false);defineExpose({init,setListObj,
});
</script><style lang="less" scoped>
.tree-box {--van-search-content-background-color: #eeeeee;--van-search-content-background: #eeeeee;
}.tree-container {width: 100%;padding: 32px 32px 0;
}.tree-data {height: 60vh;overflow-y: auto;
}.tree-btns {width: 100%;margin-bottom: 24px;display: flex;align-items: center;
}.tree-confirm {width: 100%;padding: 12px 32px;
}
</style>
tree组件
<template><div class="list"><div class="item" v-for="item in props.list" :key="item.key" v-show="!item.isHide"><div class="title"><div class="checkbox-box"><van-checkbox icon-size="16px" shape="square" @click.stop="checkChange(item)" v-model="item.checked"><span style="font-size: 15px;">{{ item.name}}</span></van-checkbox></div><div @click.stop="itemClick(item)" :class="item.first?'arrow':'arrowlast'"><van-icon v-if="item.children && item.children.length" :name="item.isShowChildren ? 'arrow-up' : 'arrow-down'" /></div></div><div class="tree" v-show="item.first||item.isShowChildren"><tree :isLink="data.isLink"v-if="item.children && item.children.length" :list="item.children" :listObj="props.listObj":isFirstFloor="false" :multiple="data.multiple" @confirm="onConfirm" :defaultId="defaultId"></tree></div></div></div>
</template>
<script setup>
import { reactive, watch } from 'vue'
import tree from './tree.vue'
const emits = defineEmits(["change","confirm"])
const props = defineProps({// 是否是第一层isFirstFloor: {type: Boolean,default() {return true;},},// 树形结构list: {type: Array,default() {return [];},},// 树形扁平化数据listObj: {type: Object,default() {return {};},},// 单选默认值defaultId : String
})const data = reactive({firstLoad: true,checkboxValue1: [],showList: [],isLink:true,multiple:true,isOutData: true, // 需要将数据抛出
})watch(() => props.list, () => {if (data.firstLoad) {outDataBuffer();data.firstLoad = false;}// 判断 是第一层树 且 不是进行显示隐藏操作时,进行数据的抛出if (props.isFirstFloor && data.isOutData) {if(data.multiple){outCheckedData();}}
}, { deep: true })// 展开
const itemClick = (item) => {outDataBuffer();item.isShowChildren = !item.isShowChildren}
// 数据抛出缓冲(在list数据变化时,不想抛出选择的数据时,调用该方法)
const outDataBuffer = () => {data.isOutData = false;setTimeout(() => {data.isOutData = true;}, 500);
}
// 获取选中对象
const getCheckData = (list) => {let deptList = [];list.forEach((itm) => {if (itm.checked) {deptList.push(itm);}if (itm.children && itm.children.length) {deptList = deptList.concat(getCheckData(itm.children));}});return deptList;
}
// 单项checked改变
const checkChange = (item) => {// 多选if (data.multiple) {// item.checked = !item.checkedif (data.isLink) {// 展开所有可以展开的节点if (item.checked) {expandAll(item);}// 判断父级是否需要勾选checkParent(item);// 勾选子级if (item.children && item.children.length) {checkChidren(item.children, item.checked);outCheckedData();}}return}// 单选if(item.children && item.children.length) returntoggleAllSelectData(props.list)outCheckedData();}// 获取全部可选择数据,进行全选/取消
const toggleAllSelectData = (list) => {list.forEach((itm) => {itm.checked = falseif (itm.children && itm.children.length) {toggleAllSelectData(itm.children)}});
}// 展开所有可以展开的节点
const expandAll = (item) => {if (item.children?.length) {item.isShowChildren = trueitem.children.forEach(itm => {expandAll(itm);})}
}
// 判断父级是否需要勾选
const checkParent = (item) => {// 父级不存在不再往下走if (!props.listObj[item[props.pidKey]]) {return;}let someDataCount = 0; // 同级的相同父级数据量let checkedDataCount = 0; // 同级已勾选的数据量for (const id in props.listObj) {const itm = props.listObj[id];if (itm[props.pidKey] === item[props.pidKey] && !itm.isHide) {someDataCount++;if (itm.checked) {checkedDataCount++;}}}const isEqual = someDataCount === checkedDataCount;if (props.listObj[item[props.pidKey]].checked != isEqual) {props.listObj[item[props.pidKey]].checked = isEqualcheckParent(props.listObj[item[props.pidKey]]);}
}
// 根据父级统一取消勾选或勾选
const checkChidren = (list, isChecked) => {list.forEach((itm) => {itm.checked = isCheckedif (itm.children && itm.children.length) {checkChidren(itm.children, isChecked);}});
}
// 抛出选中的数据
const outCheckedData = () => {const checkedList = getCheckData(props.list);emits("change", checkedList);onConfirm(checkedList)
}const onConfirm = (e) => {emits("confirm", e);
}defineExpose({itemClick,outDataBuffer,getCheckData,checkChange,expandAll,checkParent,checkChidren,outCheckedData,})
</script><style lang="less" scoped>.list {.item {margin-bottom: 10px;.title {display: flex;align-items: center;justify-content: space-between;margin-bottom: 10px;.checkbox-box {display: flex;align-items: center;cursor: pointer;padding: 10px 0;}.arrow{width: 80px;display: flex;justify-content: flex-end;}}.tree {margin-left: 50px;}}.arrow{display: none !important;}
}
</style>
数据格式
[{"name": "1","key": 0,"children": [{"name": "2","key": 1,"children": []},{"name": "3","key": 1,"children": [{"name": "4","key": 3,"children": []}]}]}
]
相关文章:

vue3+vant 实现树状多选组件
vue3vant 实现树状多选组件 需求描述效果图代码父组件引用selectTree组件 tree组件数据格式 需求描述 移动端需要复刻Pc端如上图的功能组件,但vant无组件可用,所以自己封装一个。 效果图 代码 父组件引用 import TreeSelect from "/selectTree.vu…...

Git安装与常用命令
Git简介: Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或大或小的项目。Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。Git与常用的版本控制工具CVS、Subversion等不同,它采用了分布式…...

uni-app 使用vscode开发uni-app
安装插件 uni-create-view 用于快速创建页面 配置插件 创建页面 输入页面名称,空格,顶部导航的标题,回车 自动生成页面并在pages.json中注册了路由 pages\login\login.vue <template><div class"login">login</d…...

单线程的JS中Vue导致的“线程安全”问题
目录 现象分析原因 浏览器中Js是单线程的,当然不可能出现线程安全问题。只是遇到的问题的现象与多线程的情况十分相似,导致对不了解Vue实现的我怀疑起了人生… 现象 项目中用到了element-plus中的加载组件,简单封装了一下,用来保…...

vue2 - SuperMap3D加载基于Nginx服务生成的3DTileset模型切片服务地址
文章目录 🍍开发环境🍉1:nginx发布3Dtileset模型切片服务🍍1.1:准备3DTileset文件🍍1.2:安装nginx服务,配置相关文件1.2.1:下载nginx1.2.2:下载完解压文件如下1.2.3:将3Dtileset模型文件放置 nginx-1.24.0/html/gc 新建文件中如下:1.2.4:配置nginx服务🍉2:…...

新版本Spring Security 2.7 + 用法,直接旧正版粘贴
一、以前的用法: Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}Overrideprotected void configure(HttpSecurity http) throws Exceptio…...

JVM——类加载器(JDK8及之前,双亲委派机制)
目录 1.类加载器的分类1.实现方式分类1.虚拟机底层实现2.JDK中默认提供或者自定义 2.类加载器的分类-启动类加载器3.类加载器的分类-Java中的默认类加载器4.类加载器的分类-扩展类加载器5.类加载器的分类-类加载器的继承 2.类加载器的双亲委派机制 类加载器(ClassLo…...

(七)什么是Vite——vite优劣势、命令
vite分享ppt,感兴趣的可以下载: Vite分享、原理介绍ppt 什么是vite系列目录: (一)什么是Vite——vite介绍与使用-CSDN博客 (二)什么是Vite——Vite 和 Webpack 区别࿰…...

vue之Error: Unknown option: .devServer.
背景 在使用内网穿透工具时,加入对应的配置,启动出现报错。 一、遇到的问题 报错: Error: Unknown option: .devServer. Check out https://babeljs.io/docs/en/babel-core/#options for more information about options. Error: Unknown …...

基于ssm的房屋租售网站(有报告)。Javaee项目,ssm项目。
演示视频: 基于ssm的房屋租售网站(有报告)。Javaee项目,ssm项目。 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 项目介绍: 采用M(mode…...

LeeCode AutoX-4 计算几何
题意 传送门 LeeCode AutoX-4 蚂蚁爬行 题解 枚举每一对几何图形,判断相交性,用并查集维护连通性即可。总时间复杂度 O ( n 2 m ) O(n^2 m) O(n2m),其中 n n n 为几何图形数量, m m m 为查询数量。 根据几何图形性质分类讨…...

Vue3 动态设置 ref
介绍 在一些场景,ref设置是未知的需要根据动态数据来决定,如表格中的input框需要我们主动聚焦,就需要给每一个input设置一个ref,进而进行聚焦操作。 Demo 点击下面截图中的编辑按钮,自动聚焦到相应的输入框中。 &…...

fast lio 2 保存每一帧的点云PCD和里程计矩阵 Odom 在txt文件
修改了源代码的 laserMapping.cpp 文件,替换为下面的代码就可以保存了,注意里面有一个路径,需要修改为你的电脑的路径 // This is an advanced implementation of the algorithm described in the // following paper: // J. Zhang and S. Singh. LOAM: Lidar Odometry an…...

当前主流DDos方式有哪几类
随着互联网的普及和技术的进步,网络安全问题日益凸显。DDoS攻击作为其中一种常见且具破坏性的攻击方式,受到了广泛关注。小德将带领大家一起来了解当前流行的三种DDoS攻击方式。 1. 容量耗尽攻击 容量耗尽攻击是最常见也是最直接的DDoS攻击方式。攻击者通…...

神经网络常见评价指标AUROC(AUC-ROC)、AUPR(AUC-PR)
神经网络的性能可以通过多个评价指标进行衡量,具体选择哪些指标取决于任务的性质。以下是神经网络中常见的评价指标: 准确性(Accuracy): 准确性是最常见的分类任务评价指标,表示模型正确预测的样本数占总样…...

Apache Doris安装部署
Apache Doris安装部署 版本: CentOS 7.6 Apache Doris 0.14.0 编译 选择合适的版本进行下载,此次选择0.14.0版本 下载 | Apache Doris 一、CentOS编译 1 安装依赖 sudo yum groupinstall Development Tools && sudo yum install maven c…...

Excel查询时用vlookup或者xlookup时,虽然用的参数选择的是精确匹配,但是发现不能区分大小写,应该如何解决?
Excel查询时用vlookup或者xlookup时,虽然用的参数选择的是精确匹配,但是发现不能区分大小写,应该如何解决? Index函数解决 INDEX([excel1.xlsx]Sheet1!$E:$E,MATCH(1,EXACT(G5,[excel1.xlsx]Sheet1!$E:$E)*1,0))重点说明&#x…...

4种经典的限流算法
0、基础知识 1000毫秒内,允许2个请求,其他请求全部拒绝。 不拒绝就可能往db打请求,把db干爆~ interval 1000 rate 2; 一、固定窗口限流 固定窗口限流算法(Fixed Window Rate Limiting Algorithm)是…...
<MySQL> 什么是数据库事务?事务该如何使用?
目录 一、事务的概念 二、事务的核心特性 三、事务操作中的常见BUG 3.1 脏读 3.2 不可重复读 3.3 幻读 四、隔离级别 五、使用事务 一、事务的概念 “事务”是指一组操作,在逻辑上是不可分割的,组成这组操作的各个语句,或者全部执行成…...

Linux 网络:PMTUD 简介
文章目录 1. 前言2. Path MTU Discovery(PMTUD) 协议2.1 PMTUD 发现最小 MTU 的过程 3. Linux 的 PMTUD 简析3.1 创建 socket 时初始化 PMTUD 模式3.2 数据发送时 PMTUD 相关处理3.2.1 源头主机发送过程中 PMTU 处理3.2.2 转发过程中 PMTUD 处理 4. PMTUD 观察5. 参考链接 1. 前…...

BatchNormalization:解决神经网络中的内部协变量偏移问题
ICML2015 截至目前51172引 论文链接 代码连接(planing) 文章提出的问题 减少神经网络隐藏层中的”内部协变量偏移”问题。 在机器学习领域存在“协变量偏移”问题,问题的前提是我们划分数据集的时候,训练集和测试集往往假设是独立同分布(i.i.d)的,这种独立同分布更有利于…...

DAC实验(DAC 输出三角波实验)(DAC 输出正弦波实验)
DAC 输出三角波实验 本实验我们来学习使用如何让 DAC 输出三角波,DAC 初始化部分还是用 DAC 输出实验 的,所以做本实验的前提是先学习 DAC 输出实验。 使用 DAC 输出三角波,通过 KEY0/KEY1 两个按键,控制 DAC1 的通道 1 输出两种…...

许多网友可能还不知道,升级到Windows 11其实没那么复杂,只要符合几个条件可以了
如果你的Windows 10电脑可以升级Windows 11,现在怎么办?有几种方法可以免费安装新的操作系统。以下是你的选择。 如果你想升级到Windows 11,你可以随时购买一台已经安装了操作系统的新电脑。然而,如果你目前的Windows 10 PC满足所有必要的升级要求,那么在Windows 11免费的…...

ubuntu下载conda
系统:Ubuntu18.04 (1)下载安装包 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2021.11-Linux-x86_64.sh 报错错误 403:Forbidden 解决方法 wget -U NoSuchBrowser/1.0 https://mirrors.tuna.tsingh…...

重磅 | 进一步夯实生态建设,朗思科技与阿里龙蜥完成兼容性认证
近日,北京朗思智能科技有限公司(以下简称“朗思科技”)自主研发的数字员工产品与OpenAnolis龙蜥社区龙蜥操作系统(Anolis OS)8完成兼容性认证。测试结果显示,双方产品相互兼容,功能正常…...

Qt给控件添加图片
双击qrc文件,选择下面的addFiles,将图片添加进来,然后选中图片右键Select All 设置控件字符: ui.btnSet->setText(""); 设置资源: ui.btnSet->setStyleSheet("QPushButton{background-image:…...

3.6-Dockerfile语法梳理及最佳实践
WORKDIR是设置当前docker的工作目录 ADD 和 COPY 为了将本地的一些文件添加到docker image里面,ADD 和 COPY的作用特别像,但是ADD 和 COPY还有一些区别,ADD不仅可以添加本地文件到docker里面,还可以将文件在添加到docker image里面…...

springboot集成nacos并实现自动刷新
目录 1.说明 2.示例 3.自动刷新的注意点 1.说明 springboot项目中存在好多配置文件,比如配置数据信息,redis信息等等,配置文件可以直接放在代码,也可以放在像nacos这样的组件中,实现动态的管理,修改配置…...

java面试八股文2023完整版详解110题附带答案
以下是一份Java面试八股文2023,涵盖了Java编程语言的核心概念和常用技术,帮助你更好地准备面试。 1. Java语言有哪些特点? Java语言是一种面向对象的编程语言,具有简单、面向对象、分布式、多线程、动态等优点。它是一种跨平台的…...

微服务实战系列之Token
前言 什么是“Token”? 它是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便返回给客户端;以后客户端只携带此Token请求数据即可。 简言之,Token其实就是用户身…...