vue3 elementPlus中el-tree-select封装和自定义模糊搜索
:filter-node-method="filterNodeMethod"此方法对应的是模糊搜索,// 获取树形数据
const loadTreeData = async () => {try {const res = await deviceTree()if (res.data) {treeData.value = res.data// 构建 ID 到标签的映射idMap.value = new Map()const buildMap = (nodes) => {nodes.forEach((node) => {idMap.value.set(node.id, node.label)if (node.children) buildMap(node.children)})}buildMap(res.data)isDataLoaded.value = true}} catch (error) {console.error('获取树形数据失败:', error)}
}
剩余都是正常的通信,根据自己需要增加参数,下面是整体代码
<template><div class="custom-tree-select"><el-tree-selectv-model="selectedValue"ref="treeSelectRef":data="treeData"multiple:max-collapse="2"collapse-tagscollapse-tags-tooltipshow-checkbox:filter-node-method="filterNodeMethod"filterablenode-key="id":props="defaultProps":style="{ width: width }"@check="handleCheck"clearable@clear="handleClear":placeholder="placeholder":default-expanded-keys="['1']":max-tag-count="maxTagCount":max-collapse-tags="maxCollapseTags"@remove-tag="handleRemoveTag":max-tag-placeholder="() => `已选${selectedValue.length}个`"><!-- 自定义折叠标签显示 --><template #collapse-tag><div class="custom-collapse-tag">已选择 {{ selectedValue.length }} 个设备</div></template></el-tree-select></div>
</template><script setup>
import { ref } from 'vue'
import { deviceTree } from '@/api/positioning/apiPositioning'const props = defineProps({width: {type: String,default: '100%',},placeholder: {type: String,default: '请选择设备',},maxTagCount: {type: Number,default: 2},maxCollapseTags: {type: Number,default: 1 // 设置显示的标签数量}
})const emit = defineEmits(['update:deviceIds', 'update:selectedIds'])const treeSelectRef = ref(null)
const treeData = ref([])
const selectedValue = ref([])
const idMap = ref(new Map())
const isDataLoaded = ref(false)const handleClear = () => {emit('update:selectedIds', [])emit('update:deviceIds', [])
}// 树形配置
const defaultProps = {children: 'children',label: 'label',
}// 处理节点选中状态变化
const handleCheck = (data, { checkedNodes }) => {// 过滤出最后一层且有 deviceId 的节点const leafNodes = checkedNodes.filter((node) => {return (!node.children || node.children.length == 0) && node.deviceId})// 更新选中的节点ID和设备ID// selectedValue.value = leafNodes.map((node) => node.id)const deviceIds = leafNodes.map((node) => node.deviceId)// 向父组件发送更新事件emit('update:selectedIds', selectedValue.value)emit('update:deviceIds', deviceIds)
}// 获取树形数据
const loadTreeData = async () => {try {const res = await deviceTree()if (res.data) {treeData.value = res.data// 构建 ID 到标签的映射idMap.value = new Map()const buildMap = (nodes) => {nodes.forEach((node) => {idMap.value.set(node.id, node.label)if (node.children) buildMap(node.children)})}buildMap(res.data)isDataLoaded.value = true}} catch (error) {console.error('获取树形数据失败:', error)}
}// 提供重置方法
const reset = () => {selectedValue.value = []if (treeSelectRef.value) {treeSelectRef.value.setCheckedKeys([])}emit('update:selectedIds', [])emit('update:deviceIds', [])
}// 添加删除标签的处理函数
const handleRemoveTag = (removedTag) => {// 从选中值中移除被删除的标签selectedValue.value = selectedValue.value.filter(id => id !== removedTag)// 更新树形控件的选中状态if (treeSelectRef.value) {treeSelectRef.value.setCheckedKeys(selectedValue.value)}// 获取当前选中的叶子节点const checkedNodes = treeSelectRef.value.getCheckedNodes()const leafNodes = checkedNodes.filter(node => !node.children || node.children.length === 0)const deviceIds = leafNodes.map(node => node.deviceId)// 发送更新事件emit('update:selectedIds', selectedValue.value)emit('update:deviceIds', deviceIds)
}const filterNodeMethod = (value, data) => {if (!isDataLoaded.value) return falseif (!value) return trueconst searchValue = value.toLowerCase()const traverse = (node) => {if (node.label && node.label.toLowerCase().includes(searchValue)) {return true}if (node.children) {for (const child of node.children) {if (traverse(child)) {return true}}}return false}return traverse(data)
}// 暴露方法给父组件
defineExpose({reset,treeSelectRef,
})// 初始化加载数据
loadTreeData()
</script><style lang="scss" scoped>
.custom-tree-select {:deep(.el-tree-select) {.el-select__tags {max-width: calc(100% - 30px);overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}// 自定义折叠标签样式.custom-collapse-tag {display: inline-flex;align-items: center;height: 24px;padding: 0 8px;font-size: 12px;color: var(--el-text-color-regular);background: var(--el-fill-color-light);border-radius: 4px;}// 调整标签间距.el-select__tags-text {margin-right: 4px;}}
}
</style>