当前位置: 首页 > 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.rkmt.cn/news/1475701.html

相关文章:

  • 2026实力之选:上海钧直进出口有限公司——高速混匀与脱泡技术的专业品牌 - 品牌企业推荐师(官方)
  • 2026上海装修公司推荐:8家靠谱品牌横评,从性价比到智能住宅怎么选?
  • 植物大战僵尸开源修改器PvZ Toolkit:让经典游戏焕发第二春的终极方案!
  • 实战演示:用快马平台快速搭建高保真产品demo,用于客户汇报与用户测试
  • Python学习之路:range()
  • 开发VS2026插件最佳方案:老式VSIX EnvDTE
  • CSDN后台数据不告诉你的事,站内搜索、推荐流、外部SEO流量如何用HTTP Referer+User-Agent+Session ID三重交叉验证?
  • SideJITServer终极指南:如何在iOS 17设备上实现无线JIT编译
  • OpenClaw 技能开发决策报告:脚本内置分析逻辑 vs. 框架原生调用
  • 【JVM】根可达算法
  • 实战应用:基于快马平台快速开发具备平滑过渡动画的网页日夜主题切换器
  • 效率提升秘籍:用claude code在快马平台自动生成通用工具函数库
  • 澳洲集运公司推荐:适配方案汇总 - 资讯速览
  • 鸣潮自动化:如何让游戏帮你打工,每天节省3小时重复操作?
  • 工程师如何构建抗压系统:从技术调试到职业韧性
  • FastGithub:5分钟搭建专属GitHub加速通道,告别访问卡顿
  • SpringSecurity源码初探
  • 大语言模型辅助智能合约静态审计:利用 AST 语法树解析与 LLM 提示词链漏洞扫描实战
  • 2026年工衣/防静电工衣/电子厂工衣/食品厂工衣/夏天工衣供应厂家分析:透气舒适与安全防护双优之选 - 品牌企业推荐师(官方)
  • YOLO26红外小目标检测实战:缝合DASI模块,实现暗光环境下的特征极速增强
  • Android应用保活技术突破:基于Linux特性的永生方案实现
  • Vidupe:智能视频去重工具,彻底解决重复视频存储问题
  • 智微JM系列桥接芯片选型、设计与实战指南
  • Hermes+Obsidian打造终身可用的AI知识库
  • 公司电话号码认证服务商哪家好?2026最新实力推荐 - 企业服务推荐
  • 工业防爆监控硬件原理与浙江工矿场景选型方案详解
  • 组件库工程底座:基于 TypeScript + Rollup 的多端通用(ESM/CommonJS)高质量组件打包体系搭建
  • 联发科三款芯片折戟启示录:技术选型、量产与市场节奏的硬核复盘
  • B2B网站如何做谷歌排名优化?多语言乱码报错的3个排雷技巧
  • 2026座机号码认证服务商推荐,智合聚通合规又靠谱 - 企业服务推荐