vue3 elementPlus中el-tree-select封装和自定义模糊搜索

发布于:2025-04-19 ⋅ 阅读:(58) ⋅ 点赞:(0)
: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-select
      v-model="selectedValue"
      ref="treeSelectRef"
      :data="treeData"
      multiple
      :max-collapse="2"
      collapse-tags
      collapse-tags-tooltip
      show-checkbox
      :filter-node-method="filterNodeMethod"
      filterable
      node-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 false
  if (!value) return true
  const 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>


网站公告

今日签到

点亮在社区的每一天
去签到