当前位置: 首页 > news >正文

el-tree 二次封装 含搜索

<template>
<div class="smart-tree-radio">
<el-input
v-model="keyword"
clearable
placeholder="请输入关键字搜索"
class="smart-tree-radio__search"
/>

<el-tree
ref="treeRef"
:data="filterTreeData"
:props="treeProps"
node-key="value"
default-expand-all
:expand-on-click-node="false"
>
<template #default="{ data }">
<el-radio
class="smart-tree-radio__radio"
:model-value="innerValue"
:value="data.value"
:disabled="data.disabled"
@change="handleRadioChange(data)"
>
{{ data.label }}
</el-radio>
</template>
</el-tree>

<div class="smart-tree-radio__footer">
<el-button size="small" @click="handleClear">清空</el-button>
</div>
</div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import type { ElTree } from 'element-plus'

interface TreeItem {
label: string
value: string | number
disabled?: boolean
children?: TreeItem[]
}

const props = withDefaults(
defineProps<{
modelValue?: string | number | null
data: TreeItem[]
}>(),
{
modelValue: null,
data: () => []
}
)

const emit = defineEmits<{
'update:modelValue': [value: string | number | null]
change: [node: TreeItem | null]
}>()

const treeRef = ref<InstanceType<typeof ElTree>>()

const keyword = ref('')
const innerValue = ref<string | number | null>(props.modelValue)

const treeProps = {
label: 'label',
children: 'children'
}

/**
* 搜索核心:
* 命中当前节点,保留当前节点;
* 命中子节点,也保留父级路径。
*/
const filterTreeData = computed(() => {
const key = keyword.value.trim()

if (!key) return props.data

const loop = (list: TreeItem[]): TreeItem[] => {
return list.reduce<TreeItem[]>((result, item) => {
const children = item.children ? loop(item.children) : []
const selfMatched = item.label.includes(key)

if (selfMatched || children.length) {
result.push({
...item,
children
})
}

return result
}, [])
}

return loop(props.data)
})

/**
* 外部传 value 后,支持反显。
*/
watch(
() => props.modelValue,
value => {
innerValue.value = value ?? null
},
{
immediate: true
}
)

/**
* el-radio 单选:
* 只改变当前节点 value;
* 不影响父级,不影响子级。
*/
const handleRadioChange = (data: TreeItem) => {
if (data.disabled) return

innerValue.value = data.value

emit('update:modelValue', data.value)
emit('change', data)
}

/**
* 清空:
* 清空当前选中 value。
*/
const handleClear = () => {
innerValue.value = null

emit('update:modelValue', null)
emit('change', null)
}
</script>

<style scoped lang="scss">
.smart-tree-radio {
width: 100%;

&__search {
margin-bottom: 8px;
}

&__radio {
width: 100%;
height: 26px;
display: flex;
align-items: center;
}

&__footer {
margin-top: 8px;
text-align: right;
}
}
</style>

http://www.jsqmd.com/news/964010/

相关文章:

  • Rancher2.0搭建kubernetes(K8S)集群
  • 新手零基础入门:借助快马AI生成你的第一个Node.js服务器项目
  • 与SpringSecurity的初次邂逅
  • YOLO26小目标检测涨点神技:引入SPD-Conv(空间深度转换)解决低分辨率痛点
  • 实战演示:用快马平台快速搭建高保真产品demo,用于客户汇报与用户测试
  • 海康威视NVR接入开发
  • FPGA按键消抖:移位寄存器边沿检测原理与工程实现
  • 2026上海装修公司推荐:8家靠谱品牌横评,从性价比到智能住宅怎么选?
  • 2026实力之选:上海钧直进出口有限公司——高速混匀与脱泡技术的专业品牌 - 品牌企业推荐师(官方)
  • 植物大战僵尸开源修改器PvZ Toolkit:让经典游戏焕发第二春的终极方案!
  • 【私域引流风控急救指南】:CSDN AI数字营销能否48小时内解除平台封禁?3大实测验证路径曝光
  • DbGate:一个能管16种数据库的跨平台客户端
  • Voron 2.4终极指南:开源CoreXY 3D打印机如何重新定义高速打印体验
  • 从CAN总线通信失效解析汽车电子系统可靠性:以大众DSG“死亡闪烁”为例
  • CSDN后台数据不告诉你的事,站内搜索、推荐流、外部SEO流量如何用HTTP Referer+User-Agent+Session ID三重交叉验证?
  • Python亚马逊SP-API实战指南:5步构建高效电商自动化系统
  • AI赋能:让快马平台智能解析任意GitHub项目并自动生成代码架构报告
  • Python学习之路:range()
  • 让ai成为你的hermes专家:在快马平台实现智能代码优化与性能调优
  • 开发VS2026插件最佳方案:老式VSIX EnvDTE
  • USB-C供电标准化:从接口统一到产业链变革的深度解析
  • 如何高效使用JewelCraft:Blender珠宝设计插件的专业快速上手教程
  • SideJITServer终极指南:如何在iOS 17设备上实现无线JIT编译
  • 从青铜器锈层识别到唐三彩釉料逆向建模:12个已落地AI-古董融合案例深度拆解
  • 保姆级教程:在Ubuntu 20.04上搞定HBase 2.1.1伪分布式,数据存到Hadoop 2.7的HDFS里
  • LED芯片选型实战:从Lumileds新K2看光效、热阻与驱动设计
  • 上海普陀区黄金回收实体店,现场光谱测金,报价 = 到手实收价 - 奢侈品回收评测
  • Qt项目混合开发实战:用QQuickWidget把QML界面嵌入老Widgets项目(附透明背景与事件穿透避坑指南)
  • 6.登录认证
  • OpenClaw 技能开发决策报告:脚本内置分析逻辑 vs. 框架原生调用