Element Plus搜索功能:全局搜索与筛选过滤实现

Element Plus搜索功能:全局搜索与筛选过滤实现

【免费下载链接】element-plus element-plus/element-plus: Element Plus 是一个基于 Vue 3 的组件库,提供了丰富且易于使用的 UI 组件,用于快速搭建企业级桌面和移动端的前端应用。 【免费下载链接】element-plus 项目地址: https://gitcode.com/GitHub_Trending/el/element-plus

还在为复杂数据表格的搜索筛选而头疼?Element Plus提供了强大的搜索和过滤功能,让数据查询变得简单高效。本文将深入解析Element Plus的搜索过滤机制,从基础组件到高级应用场景,助你构建专业级的数据搜索体验。

搜索过滤功能全景图

Element Plus的搜索过滤功能覆盖了多种组件类型,形成了一个完整的搜索生态系统:

mermaid

基础搜索组件实战

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的搜索过滤功能为开发者提供了完整的解决方案,从简单的输入框搜索到复杂的组合查询,都能轻松实现。关键要点包括:

  1. 组件化思维:合理选择ElAutocomplete、ElSelect、ElTable等组件
  2. 性能优先:使用防抖、分页、虚拟滚动等技术优化性能
  3. 用户体验:提供清晰的搜索反馈和结果展示
  4. 扩展性:支持自定义过滤方法和搜索逻辑

通过本文的实战示例,你应该能够熟练运用Element Plus的各种搜索过滤功能,构建出既美观又高效的数据查询界面。记住,好的搜索体验是提升用户满意度的关键因素之一。

下一步学习建议

  • 探索远程搜索和异步加载的实现
  • 学习自定义过滤器的创建和使用
  • 了解搜索历史和建议功能的实现
  • 研究搜索结果的排序和权重计算

掌握这些高级技巧,你将能够构建出真正专业级的企业应用搜索系统。


如果本文对你有帮助,欢迎点赞、收藏、关注三连支持!后续将带来更多Element Plus高级用法解析。

【免费下载链接】element-plus element-plus/element-plus: Element Plus 是一个基于 Vue 3 的组件库,提供了丰富且易于使用的 UI 组件,用于快速搭建企业级桌面和移动端的前端应用。 【免费下载链接】element-plus 项目地址: https://gitcode.com/GitHub_Trending/el/element-plus

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值