vue实现搜索商品
Vue 实现搜索商品功能
在 Vue 中实现搜索商品功能,通常需要结合前端交互和后端数据处理。以下是实现步骤和关键代码示例。
数据绑定与输入监听
在 Vue 组件中,使用 v-model 绑定搜索输入框的值,并通过 @input 或 @keyup 监听用户输入事件。
<template>
<div>
<input
v-model="searchQuery"
@input="handleSearch"
placeholder="搜索商品..."
/>
<ul v-if="filteredProducts.length">
<li v-for="product in filteredProducts" :key="product.id">
{{ product.name }} - {{ product.price }}
</li>
</ul>
<p v-else>暂无商品</p>
</div>
</template>
搜索逻辑实现
在 methods 中定义搜索方法,根据输入内容过滤商品列表。如果是本地数据,直接使用 JavaScript 的 filter 方法;若需调用接口,则发送请求。
<script>
export default {
data() {
return {
searchQuery: '',
products: [], // 初始商品列表
filteredProducts: [] // 过滤后的结果
}
},
methods: {
handleSearch() {
if (this.searchQuery.trim() === '') {
this.filteredProducts = this.products;
return;
}
this.filteredProducts = this.products.filter(product =>
product.name.toLowerCase().includes(this.searchQuery.toLowerCase())
);
}
},
mounted() {
// 模拟初始化商品数据
this.products = [
{ id: 1, name: '手机', price: 1999 },
{ id: 2, name: '笔记本电脑', price: 5999 }
];
this.filteredProducts = this.products;
}
}
</script>
防抖优化
频繁触发搜索可能导致性能问题,可以通过防抖(debounce)优化。使用 Lodash 或手动实现防抖函数。
import debounce from 'lodash/debounce';
export default {
methods: {
handleSearch: debounce(function() {
// 搜索逻辑
}, 300)
}
}
接口请求示例
若需从后端获取搜索结果,使用 axios 或 fetch 发送请求。
async handleSearch() {
try {
const response = await axios.get('/api/products', {
params: { q: this.searchQuery }
});
this.filteredProducts = response.data;
} catch (error) {
console.error('搜索失败:', error);
}
}
样式与交互增强
添加加载状态和错误提示,提升用户体验。
<template>
<div>
<input
v-model="searchQuery"
@input="handleSearch"
placeholder="搜索商品..."
/>
<span v-if="isLoading">搜索中...</span>
<ul v-if="filteredProducts.length && !isLoading">
<!-- 商品列表 -->
</ul>
<p v-if="!filteredProducts.length && !isLoading">暂无商品</p>
<p v-if="error" class="error">{{ error }}</p>
</div>
</template>
完整组件示例
整合上述内容,以下是一个完整的 Vue 搜索组件示例:
<template>
<div class="product-search">
<input
v-model="searchQuery"
@input="handleSearch"
placeholder="输入商品名称..."
class="search-input"
/>
<div v-if="isLoading" class="loading">加载中...</div>
<ul v-else class="product-list">
<li v-for="product in filteredProducts" :key="product.id" class="product-item">
<span>{{ product.name }}</span>
<span>¥{{ product.price }}</span>
</li>
</ul>
<p v-if="!filteredProducts.length && !isLoading" class="empty">无匹配商品</p>
</div>
</template>
<script>
import axios from 'axios';
import debounce from 'lodash/debounce';
export default {
data() {
return {
searchQuery: '',
products: [],
filteredProducts: [],
isLoading: false,
error: null
};
},
created() {
this.fetchProducts();
},
methods: {
fetchProducts() {
this.isLoading = true;
axios.get('/api/products')
.then(response => {
this.products = response.data;
this.filteredProducts = response.data;
})
.catch(error => {
this.error = '加载商品失败';
console.error(error);
})
.finally(() => {
this.isLoading = false;
});
},
handleSearch: debounce(function() {
if (!this.searchQuery.trim()) {
this.filteredProducts = this.products;
return;
}
this.isLoading = true;
axios.get('/api/products/search', {
params: { q: this.searchQuery }
})
.then(response => {
this.filteredProducts = response.data;
})
.catch(error => {
this.error = '搜索失败';
console.error(error);
})
.finally(() => {
this.isLoading = false;
});
}, 300)
}
};
</script>
<style>
.product-search {
max-width: 600px;
margin: 0 auto;
}
.search-input {
width: 100%;
padding: 8px;
}
.loading, .empty {
text-align: center;
padding: 10px;
}
.product-list {
list-style: none;
padding: 0;
}
.product-item {
display: flex;
justify-content: space-between;
padding: 8px;
border-bottom: 1px solid #eee;
}
.error {
color: red;
}
</style>






