Element Plus搜索功能:全局搜索与筛选过滤实现
还在为复杂数据表格的搜索筛选而头疼?Element Plus提供了强大的搜索和过滤功能,让数据查询变得简单高效。本文将深入解析Element Plus的搜索过滤机制,从基础组件到高级应用场景,助你构建专业级的数据搜索体验。
搜索过滤功能全景图
Element Plus的搜索过滤功能覆盖了多种组件类型,形成了一个完整的搜索生态系统:
基础搜索组件实战
1. ElInput + ElAutocomplete 实现智能搜索
ElAutocomplete组件提供了智能搜索建议功能,非常适合实现搜索框的自动完成:
<template>
<el-autocomplete
v-model="searchValue"
:fetch-suggestions="querySearch"
clearable
placeholder="请输入关键词搜索"
@select="handleSelect"
/>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
interface SearchItem {
value: string
id: number
}
const searchValue = ref('')
const items = ref<SearchItem[]>([])
// 加载初始数据
const loadData = () => {
return [
{ value: 'Vue.js框架', id: 1 },
{ value: 'React开发', id: 2 },
{ value: 'Angular应用', id: 3 },
{ value: 'Element Plus组件', id: 4 },
{ value: 'TypeScript编程', id: 5 }
]
}
// 搜索查询函数
const querySearch = (queryString: string, callback: any) => {
const results = queryString
? items.value.filter(createFilter(queryString))
: items.value
callback(results)
}
// 创建过滤函数
const createFilter = (queryString: string) => {
return (item: SearchItem) => {
return item.value.toLowerCase().includes(queryString.toLowerCase())
}
}
// 选择处理
const handleSelect = (item: SearchItem) => {
console.log('选中项:', item)
// 执行搜索操作
performSearch(item.value)
}
// 执行搜索
const performSearch = (keyword: string) => {
// 这里可以调用API或过滤本地数据
console.log('执行搜索:', keyword)
}
onMounted(() => {
items.value = loadData()
})
</script>
2. ElSelect filterable 属性实现下拉搜索
对于选项较多的下拉选择,filterable属性让用户能够快速找到目标选项:
<template>
<el-select
v-model="selectedValue"
filterable
placeholder="请搜索并选择"
style="width: 300px"
>
<el-option
v-for="item in filteredOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue'
const selectedValue = ref('')
const searchText = ref('')
const options = [
{ value: 'vue', label: 'Vue.js - 渐进式JavaScript框架' },
{ value: 'react', label: 'React - 用于构建用户界面的JavaScript库' },
{ value: 'angular', label: 'Angular - 平台和框架用于构建单页客户端应用' },
{ value: 'element', label: 'Element Plus - 基于Vue 3的组件库' },
{ value: 'antd', label: 'Ant Design - 企业级UI设计语言和React实现' }
]
// 计算过滤后的选项
const filteredOptions = computed(() => {
if (!searchText.value) return options
return options.filter(option =>
option.label.toLowerCase().includes(searchText.value.toLowerCase())
)
})
</script>
数据表格搜索过滤实战
3. ElTable 列过滤功能
ElTable提供了强大的列过滤功能,支持多种过滤方式:
<template>
<div>
<!-- 全局搜索 -->
<el-input
v-model="globalSearch"
placeholder="全局搜索..."
style="width: 300px; margin-bottom: 20px"
@input="handleGlobalSearch"
/>
<el-table :data="filteredData" style="width: 100%">
<el-table-column prop="name" label="姓名" width="180">
<template #header>
<div style="display: flex; align-items: center;">
<span>姓名</span>
<el-input
v-model="nameFilter"
size="small"
placeholder="过滤姓名"
style="width: 120px; margin-left: 10px"
@input="handleFilter"
/>
</div>
</template>
</el-table-column>
<el-table-column prop="age" label="年龄" width="100">
<template #header>
<div style="display: flex; align-items: center;">
<span>年龄</span>
<el-select
v-model="ageFilter"
size="small"
placeholder="选择年龄"
style="width: 100px; margin-left: 10px"
@change="handleFilter"
>
<el-option label="全部" value="" />
<el-option label="20-30" value="20-30" />
<el-option label="31-40" value="31-40" />
<el-option label="41+" value="41+" />
</el-select>
</div>
</template>
</el-table-column>
<el-table-column prop="address" label="地址" />
<el-table-column prop="status" label="状态" width="120">
<template #header>
<div style="display: flex; align-items: center;">
<span>状态</span>
<el-select
v-model="statusFilter"
size="small"
placeholder="选择状态"
style="width: 100px; margin-left: 10px"
@change="handleFilter"
>
<el-option label="全部" value="" />
<el-option label="活跃" value="active" />
<el-option label="禁用" value="inactive" />
<el-option label="待审核" value="pending" />
</el-select>
</div>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from 'vue'
interface TableData {
id: number
name: string
age: number
address: string
status: string
}
const globalSearch = ref('')
const nameFilter = ref('')
const ageFilter = ref('')
const statusFilter = ref('')
const tableData = ref<TableData[]>([])
const filteredData = computed(() => {
let result = tableData.value
// 全局搜索
if (globalSearch.value) {
const searchTerm = globalSearch.value.toLowerCase()
result = result.filter(item =>
item.name.toLowerCase().includes(searchTerm) ||
item.address.toLowerCase().includes(searchTerm) ||
item.status.toLowerCase().includes(searchTerm)
)
}
// 姓名过滤
if (nameFilter.value) {
result = result.filter(item =>
item.name.toLowerCase().includes(nameFilter.value.toLowerCase())
)
}
// 年龄过滤
if (ageFilter.value) {
const [min, max] = ageFilter.value.split('-').map(Number)
if (ageFilter.value.endsWith('+')) {
const minAge = parseInt(ageFilter.value)
result = result.filter(item => item.age >= minAge)
} else if (!isNaN(min) && !isNaN(max)) {
result = result.filter(item => item.age >= min && item.age <= max)
}
}
// 状态过滤
if (statusFilter.value) {
result = result.filter(item => item.status === statusFilter.value)
}
return result
})
const handleGlobalSearch = () => {
// 全局搜索逻辑已在computed中处理
}
const handleFilter = () => {
// 过滤逻辑已在computed中处理
}
// 生成测试数据
onMounted(() => {
tableData.value = [
{ id: 1, name: '张三', age: 25, address: '北京市朝阳区', status: 'active' },
{ id: 2, name: '李四', age: 32, address: '上海市浦东新区', status: 'active' },
{ id: 3, name: '王五', age: 28, address: '广州市天河区', status: 'inactive' },
{ id: 4, name: '赵六', age: 45, address: '深圳市南山区', status: 'pending' },
{ id: 5, name: '钱七', age: 22, address: '杭州市西湖区', status: 'active' }
]
})
</script>
4. ElTree 树形结构搜索过滤
对于树形数据结构,ElTree提供了专门的过滤方法:
<template>
<div>
<el-input
v-model="filterText"
placeholder="输入关键词过滤树节点"
style="margin-bottom: 20px; width: 300px"
/>
<el-tree
ref="treeRef"
class="filter-tree"
:data="treeData"
:props="defaultProps"
default-expand-all
:filter-node-method="filterNode"
highlight-current
/>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, onMounted } from 'vue'
import type { TreeInstance } from 'element-plus'
interface TreeNode {
id: number
label: string
children?: TreeNode[]
type?: string
description?: string
}
const filterText = ref('')
const treeRef = ref<TreeInstance>()
const treeData = ref<TreeNode[]>([])
const defaultProps = {
children: 'children',
label: 'label'
}
// 监听过滤文本变化
watch(filterText, (val) => {
treeRef.value!.filter(val)
})
// 自定义节点过滤方法
const filterNode = (value: string, data: TreeNode) => {
if (!value) return true
// 支持多字段搜索
const searchTerm = value.toLowerCase()
return (
data.label.toLowerCase().includes(searchTerm) ||
(data.description && data.description.toLowerCase().includes(searchTerm)) ||
(data.type && data.type.toLowerCase().includes(searchTerm))
)
}
// 生成树形测试数据
onMounted(() => {
treeData.value = [
{
id: 1,
label: '前端技术',
type: 'category',
description: '前端开发相关技术',
children: [
{
id: 11,
label: 'Vue.js',
type: 'framework',
description: '渐进式JavaScript框架'
},
{
id: 12,
label: 'React',
type: 'framework',
description: '用于构建用户界面的JavaScript库'
},
{
id: 13,
label: 'Angular',
type: 'framework',
description: '由Google维护的开源前端框架'
}
]
},
{
id: 2,
label: '后端技术',
type: 'category',
description: '后端开发相关技术',
children: [
{
id: 21,
label: 'Node.js',
type: 'runtime',
description: 'JavaScript运行时环境'
},
{
id: 22,
label: 'Spring Boot',
type: 'framework',
description: 'Java快速开发框架'
},
{
id: 23,
label: 'Django',
type: 'framework',
description: 'Python Web框架'
}
]
}
]
})
</script>
<style>
.filter-tree {
max-height: 400px;
overflow-y: auto;
}
</style>
高级搜索场景实现
5. 组合搜索与高级过滤
对于复杂的数据查询需求,可以实现组合搜索功能:
<template>
<div class="advanced-search-container">
<!-- 搜索条件面板 -->
<el-card class="search-panel">
<div class="search-fields">
<el-input
v-model="searchConditions.keyword"
placeholder="关键词搜索"
style="width: 200px"
/>
<el-select
v-model="searchConditions.category"
placeholder="选择分类"
style="width: 150px"
>
<el-option label="全部" value="" />
<el-option label="技术" value="tech" />
<el-option label="产品" value="product" />
<el-option label="设计" value="design" />
</el-select>
<el-select
v-model="searchConditions.status"
placeholder="选择状态"
style="width: 150px"
>
<el-option label="全部" value="" />
<el-option label="启用" value="active" />
<el-option label="禁用" value="inactive" />
</el-select>
<el-date-picker
v-model="searchConditions.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 300px"
/>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="resetSearch">重置</el-button>
</div>
</el-card>
<!-- 搜索结果 -->
<el-table :data="searchResults" style="width: 100%">
<el-table-column prop="title" label="标题" />
<el-table-column prop="category" label="分类" width="100" />
<el-table-column prop="status" label="状态" width="80" />
<el-table-column prop="createTime" label="创建时间" width="120" />
<el-table-column prop="author" label="作者" width="100" />
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="pagination.current"
v-model:page-size="pagination.size"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@current-change="handlePageChange"
@size-change="handleSizeChange"
/>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted } from 'vue'
interface SearchCondition {
keyword: string
category: string
status: string
dateRange: [Date, Date] | null
}
interface SearchResult {
id: number
title: string
category: string
status: string
createTime: string
author: string
content: string
}
const searchConditions = reactive<SearchCondition>({
keyword: '',
category: '',
status: '',
dateRange: null
})
const searchResults = ref<SearchResult[]>([])
const allData = ref<SearchResult[]>([])
const pagination = reactive({
current: 1,
size: 10,
total: 0
})
// 执行搜索
const handleSearch = () => {
let results = [...allData.value]
// 关键词搜索
if (searchConditions.keyword) {
const keyword = searchConditions.keyword.toLowerCase()
results = results.filter(item =>
item.title.toLowerCase().includes(keyword) ||
item.content.toLowerCase().includes(keyword) ||
item.author.toLowerCase().includes(keyword)
)
}
// 分类过滤
if (searchConditions.category) {
results = results.filter(item => item.category === searchConditions.category)
}
// 状态过滤
if (searchConditions.status) {
results = results.filter(item => item.status === searchConditions.status)
}
// 日期范围过滤
if (searchConditions.dateRange) {
const [start, end] = searchConditions.dateRange
results = results.filter(item => {
const createTime = new Date(item.createTime)
return createTime >= start && createTime <= end
})
}
// 更新分页信息
pagination.total = results.length
const start = (pagination.current - 1) * pagination.size
const end = start + pagination.size
searchResults.value = results.slice(start, end)
}
// 重置搜索
const resetSearch = () => {
searchConditions.keyword = ''
searchConditions.category = ''
searchConditions.status = ''
searchConditions.dateRange = null
handleSearch()
}
// 分页变化
const handlePageChange = (page: number) => {
pagination.current = page
handleSearch()
}
const handleSizeChange = (size: number) => {
pagination.size = size
pagination.current = 1
handleSearch()
}
// 生成测试数据
onMounted(() => {
const mockData: SearchResult[] = []
const categories = ['tech', 'product', 'design']
const statuses = ['active', 'inactive']
const authors = ['张三', '李四', '王五', '赵六']
for (let i = 1; i <= 100; i++) {
mockData.push({
id: i,
title: `文章标题 ${i}`,
category: categories[i % 3],
status: statuses[i % 2],
createTime: new Date(2024, (i % 12), (i % 28) + 1).toISOString(),
author: authors[i % 4],
content: `这是第${i}篇文章的内容,包含各种技术讨论和最佳实践分享。`
})
}
allData.value = mockData
pagination.total = mockData.length
handleSearch()
})
</script>
<style scoped>
.advanced-search-container {
padding: 20px;
}
.search-panel {
margin-bottom: 20px;
}
.search-fields {
display: flex;
gap: 12px;
align-items: center;
flex-wrap: wrap;
}
.el-pagination {
margin-top: 20px;
justify-content: center;
}
</style>
性能优化与最佳实践
搜索性能优化策略
| 优化策略 | 实现方式 | 适用场景 |
|---|---|---|
| 防抖处理 | 使用lodash debounce或自定义 | 实时搜索输入 |
| 分页加载 | 结合ElPagination组件 | 大数据集 |
| 虚拟滚动 | 使用ElTableV2或ElTreeV2 | 超大数据集 |
| 缓存机制 | 本地存储或内存缓存 | 重复查询 |
| 索引优化 | 预先建立搜索索引 | 复杂搜索条件 |
防抖搜索实现示例
<template>
<el-input
v-model="searchTerm"
placeholder="输入搜索关键词..."
@input="handleSearchInput"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { debounce } from 'lodash-es'
const searchTerm = ref('')
const isLoading = ref(false)
// 防抖搜索函数
const performSearch = debounce((term: string) => {
if (!term.trim()) return
isLoading.value = true
// 模拟API调用
setTimeout(() => {
console.log('执行搜索:', term)
isLoading.value = false
}, 500)
}, 300)
const handleSearchInput = () => {
performSearch(searchTerm.value)
}
</script>
总结与展望
Element Plus的搜索过滤功能为开发者提供了完整的解决方案,从简单的输入框搜索到复杂的组合查询,都能轻松实现。关键要点包括:
- 组件化思维:合理选择ElAutocomplete、ElSelect、ElTable等组件
- 性能优先:使用防抖、分页、虚拟滚动等技术优化性能
- 用户体验:提供清晰的搜索反馈和结果展示
- 扩展性:支持自定义过滤方法和搜索逻辑
通过本文的实战示例,你应该能够熟练运用Element Plus的各种搜索过滤功能,构建出既美观又高效的数据查询界面。记住,好的搜索体验是提升用户满意度的关键因素之一。
下一步学习建议:
- 探索远程搜索和异步加载的实现
- 学习自定义过滤器的创建和使用
- 了解搜索历史和建议功能的实现
- 研究搜索结果的排序和权重计算
掌握这些高级技巧,你将能够构建出真正专业级的企业应用搜索系统。
如果本文对你有帮助,欢迎点赞、收藏、关注三连支持!后续将带来更多Element Plus高级用法解析。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



