Appearance
BizSearchInput 搜索输入
带防抖的搜索输入框:输入实时同步 v-model,停止输入后触发 search;回车立即触发、清空触发 search('')。列表页快速过滤的轻量方案,与 BizSearchForm 互补。
基础用法
最近搜索:(未搜索)
张三李四张伟王五张小明赵六
v-model 实时绑定,@search 防抖触发(默认 300ms)。
<script setup lang="ts">
/** 基础用法:v-model 实时 + search 防抖触发(回车立即、清空触发 search('')) */
import { ref } from 'vue'
import { BizSearchInput } from 'vue3-ep-biz-lib'
const keyword = ref('')
const lastSearch = ref('(未搜索)')
const MEMBERS = ['张三', '李四', '张伟', '王五', '张小明', '赵六']
const onSearch = (value: string): void => {
lastSearch.value = value === '' ? '(空)' : value
}
</script>
<template>
<div>
<BizSearchInput v-model="keyword" placeholder="搜索成员姓名" @search="onSearch" />
<div class="tip">最近搜索:{{ lastSearch }}</div>
<div class="list">
<ElTag v-for="name in MEMBERS.filter((m) => m.includes(keyword))" :key="name" size="small">{{ name }}</ElTag>
<span v-if="MEMBERS.filter((m) => m.includes(keyword)).length === 0" class="tip">无匹配</span>
</div>
</div>
</template>
<style scoped>
.tip {
margin-top: 8px;
font-size: 13px;
color: var(--el-text-color-secondary);
}
.list {
margin-top: 8px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
</style>
显示代码
其他用法
触发记录(最新在前):(无)
防抖时长调整、隐藏搜索图标、attrs 透传(maxlength)与 #suffix 插槽。
<script setup lang="ts">
/** 其他用法:防抖时长 / 无图标 / attrs 透传(maxlength / #suffix) */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import { BizButton, BizSearchInput } from 'vue3-ep-biz-lib'
const code = ref('')
const log = ref<string[]>([])
const showValue = (): void => {
ElMessage.info(`当前值:${code.value || '(空)'}`)
}
const onSearch = (value: string): void => {
log.value = [`搜索「${value}」`, ...log.value].slice(0, 3)
}
</script>
<template>
<div>
<div class="row">
<BizSearchInput v-model="code" :debounce="800" placeholder="防抖 800ms" @search="onSearch" />
<BizSearchInput :model-value="code" :search-icon="false" maxlength="6" placeholder="无搜索图标" @search="onSearch">
<template #suffix>
<ElIcon :size="14"><Search /></ElIcon>
</template>
</BizSearchInput>
<BizButton size="small" @click="showValue">读取值</BizButton>
</div>
<div class="tip">触发记录(最新在前):{{ log.length > 0 ? log.join(' | ') : '(无)' }}</div>
</div>
</template>
<style scoped>
.row {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.tip {
margin-top: 8px;
font-size: 13px;
color: var(--el-text-color-secondary);
}
</style>
显示代码
全局搜索(范围 + 回车直达)
触发 0 次|最近检索:(未搜索)|输入停止 400ms 防抖触发 search,回车跳过等待立即触发,清空触发 search('') 复位
顶栏全局搜索场景:
prepend 范围下拉(全部 / 订单 / 用户 / 设备)与 append 图标按钮均为 Element Plus 原生融合形态(按钮/下拉在插槽内自动去边框贴合),输入停止 400ms 防抖触发 search,回车跳过等待立即触发,点击 append 按钮携带当前范围直达检索,清空触发 search('') 复位列表。宽度按场景覆盖默认 240px。<script setup lang="ts">
/** 场景:全局搜索——范围下拉 + 回车直达 + 防抖联想 */
import { computed, ref } from 'vue'
import { ElButton, ElMessage, ElOption, ElSelect } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import { BizSearchInput } from 'vue3-ep-biz-lib'
const scope = ref('all')
const keyword = ref('')
const searched = ref('(未搜索)')
const searchCount = ref(0)
const scopeOptions = [
{ label: '全部', value: 'all' },
{ label: '订单', value: 'order' },
{ label: '用户', value: 'user' },
{ label: '设备', value: 'device' },
] as const
const scopeText = computed(() => scopeOptions.find((item) => item.value === scope.value)?.label ?? '全部')
/** 防抖到期 / 回车立即 / 清空复位,统一走 search 事件 */
const onSearch = (value: string): void => {
if (value.trim() === '') {
searched.value = '(已复位)'
return
}
searchCount.value += 1
searched.value = value
}
/** append 搜索按钮:携带当前范围直达检索(真实业务为路由跳转搜索结果页) */
const onGo = (): void => {
if (keyword.value.trim() === '') {
ElMessage.warning('请输入关键词')
return
}
ElMessage.success(`在「${scopeText.value}」中检索「${keyword.value}」`)
}
</script>
<template>
<div style="max-width: 560px">
<!-- 宽度覆盖默认 240px:prepend 范围下拉 + 主输入 + append 图标按钮三段需要更宽空间 -->
<BizSearchInput
v-model="keyword"
style="width: 460px"
:debounce="400"
placeholder="搜索订单号 / 用户 / 设备,回车立即搜索"
@search="onSearch"
>
<template #prepend>
<ElSelect v-model="scope" style="width: 88px">
<ElOption v-for="item in scopeOptions" :key="item.value" :label="item.label" :value="item.value" />
</ElSelect>
</template>
<template #append>
<ElButton :icon="Search" aria-label="搜索" @click="onGo" />
</template>
</BizSearchInput>
<div style="margin-top: 8px; font-size: 13px; color: var(--el-text-color-secondary)">
触发 {{ searchCount }} 次|最近检索:{{ searched }}|输入停止 400ms 防抖触发 search,回车跳过等待立即触发,清空触发 search('') 复位
</div>
</div>
</template>
显示代码
表格即时过滤
本地过滤场景:输入即筛(防抖 300ms),清空自动复位全量——服务列表快速定位。
<script setup lang="ts">
/** 场景:表格即时过滤——输入即筛(防抖 300ms),清空复位 */
import { computed, ref } from 'vue'
import { ElTable, ElTableColumn, ElTag } from 'element-plus'
import { BizSearchInput } from 'vue3-ep-biz-lib'
const keyword = ref('')
const allRows = [
{ name: 'gateway-prod', owner: '张伟', replicas: 4, status: 'running' },
{ name: 'order-center', owner: '李娜', replicas: 6, status: 'running' },
{ name: 'report-worker', owner: '王强', replicas: 1, status: 'stopped' },
{ name: 'stock-sync', owner: '赵敏', replicas: 2, status: 'degraded' },
]
const rows = computed(() => {
const word = keyword.value.trim().toLowerCase()
if (word === '') return allRows
return allRows.filter((row) => row.name.includes(word) || row.owner.includes(word) || row.status.includes(word))
})
</script>
<template>
<div style="max-width: 560px">
<BizSearchInput v-model="keyword" placeholder="按服务名 / 负责人 / 状态即时过滤" style="margin-bottom: 10px" />
<ElTable :data="rows" size="small" border>
<ElTableColumn prop="name" label="服务" />
<ElTableColumn prop="owner" label="负责人" width="90" />
<ElTableColumn prop="replicas" label="副本" width="70" align="right" />
<ElTableColumn label="状态" width="100">
<template #default="{ row }">
<ElTag :type="row.status === 'running' ? 'success' : row.status === 'stopped' ? 'info' : 'warning'" size="small">
{{ row.status }}
</ElTag>
</template>
</ElTableColumn>
</ElTable>
</div>
</template>
显示代码
最近搜索
最近搜索:高挂空洞SPC-002光幕误触发
搜索场景:search 事件回写外部历史词(去重取前 5),点击 chip 回填输入框。
<script setup lang="ts">
/** 场景:最近搜索——外部维护历史词 chips,点击回填并搜索 */
import { ref } from 'vue'
import { ElMessage, ElTag } from 'element-plus'
import { BizSearchInput } from 'vue3-ep-biz-lib'
const keyword = ref('')
const history = ref(['高挂空洞', 'SPC-002', '光幕误触发'])
const onSearch = (value: string): void => {
const word = value.trim()
if (word === '') return
history.value = [word, ...history.value.filter((item) => item !== word)].slice(0, 5)
}
const pick = (word: string): void => {
keyword.value = word
ElMessage.info(`检索「${word}」`)
}
</script>
<template>
<div style="max-width: 520px">
<BizSearchInput v-model="keyword" placeholder="输入缺陷关键词检索" @search="onSearch" />
<div style="display: flex; gap: 8px; margin-top: 10px; align-items: center; flex-wrap: wrap">
<span style="font-size: 13px; color: var(--el-text-color-secondary)">最近搜索:</span>
<ElTag v-for="word in history" :key="word" size="small" style="cursor: pointer" @click="pick(word)">{{ word }}</ElTag>
<span v-if="history.length === 0" style="font-size: 13px; color: var(--el-text-color-placeholder)">暂无记录</span>
</div>
</div>
</template>
显示代码
防抖时长对照
debounce 300ms:输入停止 0.3s 触发(已触发 0 次)
debounce 800ms:重查询接口友好(已触发 0 次)
调参场景:300ms 与 800ms 并排对照,右侧计数器直观对比触发次数——按接口代价选防抖。
<script setup lang="ts">
/** 场景:防抖时长对照——300ms 顺滑 vs 800ms 省请求 */
import { ref } from 'vue'
import { BizSearchInput } from 'vue3-ep-biz-lib'
const fast = ref('')
const slow = ref('')
const fastCount = ref(0)
const slowCount = ref(0)
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 14px; max-width: 480px">
<div>
<p style="margin: 0 0 6px; font-size: 13px; color: var(--el-text-color-secondary)">debounce 300ms:输入停止 0.3s 触发(已触发 {{ fastCount }} 次)</p>
<BizSearchInput v-model="fast" :debounce="300" placeholder="连续输入感受触发时机" @search="() => (fastCount += 1)" />
</div>
<div>
<p style="margin: 0 0 6px; font-size: 13px; color: var(--el-text-color-secondary)">debounce 800ms:重查询接口友好(已触发 {{ slowCount }} 次)</p>
<BizSearchInput v-model="slow" :debounce="800" placeholder="连续输入感受触发时机" @search="() => (slowCount += 1)" />
</div>
<span style="font-size: 13px; color: var(--el-text-color-secondary)">两组同时连续输入 5 个字符,对比右侧触发次数</span>
</div>
</template>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| model-value / v-model | string | '' | 输入值(实时同步) |
| placeholder | string | '请输入关键词' | 占位文案 |
| debounce | number | 300 | 防抖毫秒数(输入停止后触发 search) |
| clearable | boolean | true | 可清空(清空时同步触发 search('')) |
| search-icon | boolean | true | 是否显示前缀搜索图标 |
其余属性(
maxlength/disabled...)与插槽(#prefix/#suffix...)经v-bind="$attrs"全量透传 el-input。
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| search | (value: string) | 防抖到期 / 回车 / 清空时触发(快速过滤统一入口) |
| update:model-value | (value: string) | v-model 更新 |
| clear | — | 点击清空按钮 |
Slots
| 插槽名 | 说明 |
|---|---|
| — | el-input 原生插槽经 $attrs 透传(#prefix / #suffix / #prepend...) |
Expose
| 属性/方法 | 说明 |
|---|---|
| — | 无对外暴露 |