vue3 递归无限分类树型菜单+搜索功能

我们来看一下大致实现效果,数据可以无限向下增加,搜索关键字会自动展开数据

vue3树形结构菜单+搜索

1,在components文件夹下创建vue文件,自定义递归组件

<template>
	<ul v-for="(item) in data" :key="item.id">
		<li>
			<div @click="open(item.id)">
				<p>{{item.name}}</p>
			</div>
		</li>
		<DefaultCompoent v-if="item.children&&value.includes(item.id)" :data="item.children" :key="item.id"></DefaultCompoent>
	</ul>
</template>

<script>
	import {
		computed
	} from "vue";
	import {
		PiniaStore
	} from "/src/store/index.js";
	export default {
		name: 'DefaultCompoent',
		props: {
			data: { type: Array }
		},
		setup(props) {
			// console.log(props);
			// 改变状态
			const pinia = PiniaStore();
			const checked = computed(() => {
				return pinia.searchs.length ? pinia.searchs : [];
			})
			const value = computed(() => {
				return pinia.closeList
			})
			// 打开关闭点击事件
			const open = (id) => {
				console.log(id);
				if (pinia.closeList.includes(id)) {
					pinia.closeList.splice(pinia.closeList.indexOf(id));
				} else {
					pinia.closeList.push(id);
				}
			};
			return {
				open,
				event,
				checked,
				value
			}
		}
	}
</script>

<style>
</style>

2、主页面js部分

<template>
	<section>
		<DefaultCompoent :data="tree.Arr"></DefaultCompoent>
	</section>
	<!-- 搜索框 -->
	<el-input v-model="input" placeholder="请输入搜索内容" @change="changes" />
	<router-view />
</template>

<script setup>
	import {
		ref,
		reactive,
		watch
	} from "vue";
	// import axios from "axios";
	import DefaultCompoent from '/src/components/DefaultTree.vue';
	import {
		PiniaStore
	} from "/src/store/index.js";
	const pinia = PiniaStore();
	const input = ref(''); //输入框
//模拟数据
	const tree = reactive({
		Arr: [{
				id: '1',
				name: '两栖',
				children: [{
					id: '11',
					name: '鸟类',
					children: [{
						id: '111',
						name: '飞行',
						children: [{
							id: '1111',
							name: '小鸟',
						}]
					}]
				}]
			},
			{
				id: '2',
				name: '2',
				children: [{
					id: '22',
					name: '22',
					children: [{
						id: '222',
						name: '222',
					}]
				}]
			}
		],
	});
	// 查找字段
	var num = 1;
	// console.log(data);
	const finds = (arr, field, original) => {
		console.log(arr);
		//正则匹配,只要存在该字段就会匹配成功
		let reg = new RegExp(field);
		for (let i = 0; i < arr.length; i++) {
			let res = field,
				raw = original;
			if (reg.test(arr[i].name)) {
				pinia.searchs.push(arr[i].id);
				num = 1; //每次匹配成功初始num
				unfold(original, arr[i]);
				if (arr[i].children) {
					// 若有匹配成功的字段就继续
					finds(arr[i].children, res, raw);
				}
			} else {
				//若匹配不成功,并且还有下级则再次调用自己并将下级数组传过去
				if (arr[i].children != undefined && arr[i].children.length != 0) {
					finds(arr[i].children, res, raw);
				}
			}
		}
	};
	// 将匹配到的数据id分割拿到这条数据的所有上级id
	const unfold = (raw, data) => {
		console.log(raw, data);
		if (raw != undefined && raw.length != 0) {
			// let news = [...raw];
			let id = data.id.slice(0, num); //切割id
			// console.log(id);
			pinia.closeList.push(id); //全局状态就拿到这条数据上级的所有id包括自己
			let res = raw.findIndex((val) => val.id == id);
			if (res != -1 && raw[res].children != undefined) {
				//这条数据还有下级则继续分割id
				num += 1;
				let obj = data;
				unfold(raw[res].children, obj);
			}
			tree.arr = raw;
		} else {
			num = 1;
		}
	};
	const changes = () => {
		// console.log(input.value)
		// 初始数据
		tree.arr = [];
		pinia.closeList = [];
		pinia.searchs = [];
		num = 1;
		let arr = JSON.parse(JSON.stringify(tree.Arr));
		console.log(arr);
		if (input.value != "") {
			console.log(arr);
			finds(arr, input.value, arr);
		} else {
			tree.arr = JSON.parse(JSON.stringify(tree.Arr));
			pinia.closeList = [];
			pinia.searchs = [];
			console.log(tree.arr);
		}
	};
//监听input输入的值,当输入框的值为空,树形结构自动闭合
	watch(input, (newName, oldName) => {
	  console.log(newName);
	  if(newName==''){
		  pinia.closeList = [];
		  pinia.searchs = [];
	  }
	});
</script>

<style>

</style>

ps:其中请求数据部分,我用的是模拟数据,大家可以根据自己的需求来换成接口数据;这只是一个小demo,没有过多修饰样式,有需要的小伙伴可自行调整下样式~

大致就是以上内容啦~如有不对,或者更好的解决的方案,可以一起交流

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值