1. Vue列表过滤与排序的核心价值
在Web应用开发中,数据展示是最基础也最频繁的需求之一。以电商平台为例,商品列表往往需要支持按价格排序、按分类筛选等交互功能。传统DOM操作方式不仅性能低下,代码也难以维护。Vue的响应式特性配合计算属性(computed),让这类需求变得异常简单。
我曾接手过一个遗留项目,其中用jQuery实现的商品筛选逻辑超过800行代码,改用Vue重构后仅用不到100行就实现了更强大的功能。这种开发效率的提升,正是Vue在现代前端开发中广受欢迎的原因。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础环境搭建
2.1 初始化Vue项目
推荐使用Vite创建项目,相比传统webpack方案,Vite的冷启动速度能提升10倍以上:
bash复制npm create vite@latest vue-filter-demo --template vue
cd vue-filter-demo
npm install
2.2 准备模拟数据
在src/data/products.js中创建测试数据:
javascript复制export default [
{ id: 1, name: 'iPhone 13', category: '手机', price: 5999, stock: 32 },
{ id: 2, name: 'MacBook Pro', category: '电脑', price: 12999, stock: 12 },
// 更多数据...
]
3. 实现基础列表渲染
3.1 组件基础结构
vue复制<template>
<div class="product-list">
<div v-for="product in products" :key="product.id">
{{ product.name }} - ¥{{ product.price }}
</div>
</div>
</template>
<script>
import products from './data/products'
export default {
data() {
return {
products: products
}
}
}
</script>
关键点:始终为v-for设置唯一的key,这是Vue高效更新DOM的基础
4. 实现过滤功能
4.1 添加搜索输入框
vue复制<template>
<input
v-model="searchQuery"
placeholder="搜索商品..."
class="search-input"
>
</template>
<script>
export default {
data() {
return {
searchQuery: ''
}
}
}
</script>
4.2 创建过滤计算属性
javascript复制computed: {
filteredProducts() {
const query = this.searchQuery.toLowerCase()
return this.products.filter(product => {
return product.name.toLowerCase().includes(query) ||
product.category.toLowerCase().includes(query)
})
}
}
性能提示:对于超大型列表(>1000项),考虑使用Web Worker或分页方案
5. 实现多条件排序
5.1 排序状态管理
javascript复制data() {
return {
sortField: 'price',
sortDirection: 'asc' // or 'desc'
}
}
5.2 增强版排序计算属性
javascript复制computed: {
sortedProducts() {
return [...this.filteredProducts].sort((a, b) => {
let modifier = 1
if (this.sortDirection === 'desc') modifier = -1
if (a[this.sortField] < b[this.sortField]) return -1 * modifier
if (a[this.sortField] > b[this.sortField]) return 1 * modifier
return 0
})
}
}
5.3 表头排序交互
vue复制<template>
<table>
<thead>
<tr>
<th @click="changeSort('name')">
名称
<SortIndicator field="name" />
</th>
<th @click="changeSort('price')">
价格
<SortIndicator field="price" />
</th>
</tr>
</thead>
<!-- ... -->
</table>
</template>
<script>
methods: {
changeSort(field) {
if (this.sortField === field) {
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc'
} else {
this.sortField = field
this.sortDirection = 'asc'
}
}
}
</script>
6. 性能优化技巧
6.1 防抖处理搜索输入
javascript复制import { debounce } from 'lodash'
export default {
data() {
return {
searchQuery: '',
debouncedSearch: ''
}
},
created() {
this.debouncedUpdate = debounce(() => {
this.debouncedSearch = this.searchQuery
}, 300)
},
watch: {
searchQuery() {
this.debouncedUpdate()
}
},
computed: {
filteredProducts() {
// 使用debouncedSearch代替searchQuery
}
}
}
6.2 虚拟滚动优化
对于超长列表(>1000项),使用vue-virtual-scroller:
bash复制npm install vue-virtual-scroller
vue复制<template>
<RecycleScroller
:items="sortedProducts"
:item-size="50"
key-field="id"
>
<template v-slot="{ item }">
<!-- 渲染单个商品 -->
</template>
</RecycleScroller>
</template>
7. 常见问题排查
7.1 排序不生效
可能原因:
- 原始数据被意外修改 - 使用
[...array]创建新数组 - 排序字段存在null/undefined - 添加默认值处理
javascript复制sort((a, b) => {
const valA = a[this.sortField] || 0
const valB = b[this.sortField] || 0
// ...
})
7.2 过滤结果异常
调试技巧:
- 在计算属性中添加console.log
- 检查字符串大小写处理
- 验证数据类型的匹配性
8. 高级应用场景
8.1 多列组合排序
javascript复制computed: {
sortedProducts() {
return [...this.filteredProducts].sort((a, b) => {
// 主排序字段
if (a[this.primarySort] !== b[this.primarySort]) {
return a[this.primarySort] > b[this.primarySort] ? 1 : -1
}
// 次排序字段
return a[this.secondarySort] > b[this.secondarySort] ? 1 : -1
})
}
}
8.2 服务端排序分页
对于大数据集,建议在后端处理排序:
javascript复制async fetchProducts() {
const res = await axios.get('/api/products', {
params: {
sort: this.sortField,
order: this.sortDirection,
page: this.currentPage
}
})
this.products = res.data
}
9. 单元测试要点
使用Vitest编写测试用例:
javascript复制import { computed } from 'vue'
import { useProductSort } from './useProductSort'
test('should sort products by price asc', () => {
const { sortedProducts } = useProductSort(
[{ price: 300 }, { price: 100 }, { price: 200 }],
computed(() => 'price'),
computed(() => 'asc')
)
expect(sortedProducts.value).toEqual([
{ price: 100 }, { price: 200 }, { price: 300 }
])
})
10. 样式优化建议
10.1 排序指示器动画
css复制.sort-arrow {
transition: transform 0.2s ease;
}
.sort-arrow.desc {
transform: rotate(180deg);
}
10.2 斑马纹表格
css复制.product-item:nth-child(even) {
background-color: #f5f5f5;
}
在实际项目中,我发现将过滤和排序逻辑提取到自定义hook中能显著提高代码复用性。例如创建useListFilter.js和useListSort.js组合式函数,可以在不同组件间共享相同的业务逻辑。这种模式在管理后台等需要大量表格展示的场景中特别有用。
