各位掘友,大家好!我是你们的老朋友,今天咱们来聊聊 Vue 应用中的搜索功能,保证让你的应用像装了涡轮增压一样快!
开场白:搜索,应用的灵魂伴侣
话说回来,一个好的搜索功能,就像是应用的灵魂伴侣。用户想找什么,嗖的一下就出来,体验简直不要太好!但是呢,要实现一个用户体验良好的搜索功能,可不是简单的输入框 + filter
就能搞定的。咱们今天就来深入剖析一下,如何打造一个功能强大、体验优秀的 Vue 搜索功能。
第一部分:需求分析和技术选型
在开始撸代码之前,咱们先来捋一捋需求,明确目标,才能事半功倍嘛!
-
核心功能:
- 模糊搜索: 用户输入关键词,能够匹配到包含关键词的相关内容。
- 高亮显示: 将搜索结果中的关键词高亮显示,让用户一眼就能看到重点。
- 搜索建议(自动补全): 在用户输入时,提供相关的搜索建议,提高搜索效率。
- 历史记录: 记录用户的搜索历史,方便用户快速搜索。
-
技术选型:
- Vue.js: 毋庸置疑,咱们的主角。
- Vuex (可选): 如果应用规模较大,需要共享搜索历史记录,建议使用 Vuex 进行状态管理。
- lodash (可选): 提供一些实用的工具函数,比如
debounce
防抖函数,防止用户频繁输入导致不必要的请求。 - CSS: 用于样式美化,让搜索框看起来更漂亮。
第二部分:核心功能实现
好啦,需求明确了,技术也选好了,咱们开始进入正题,撸起袖子写代码!
1. 模糊搜索
模糊搜索的实现方式有很多种,最简单的方式就是使用 JavaScript 的 String.prototype.includes()
方法。
<template>
<div>
<input type="text" v-model="searchText" placeholder="请输入关键词">
<ul>
<li v-for="(item, index) in filteredData" :key="index">{{ item.name }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
searchText: '',
data: [
{ id: 1, name: 'Apple iPhone 13' },
{ id: 2, name: 'Samsung Galaxy S22' },
{ id: 3, name: 'Xiaomi 12 Pro' },
{ id: 4, name: 'OnePlus 10 Pro' },
],
};
},
computed: {
filteredData() {
if (!this.searchText) {
return this.data;
}
return this.data.filter(item =>
item.name.toLowerCase().includes(this.searchText.toLowerCase())
);
},
},
};
</script>
这段代码的核心在于 filteredData
这个计算属性。它会根据 searchText
的值,过滤 data
数组,只保留包含 searchText
的元素。为了保证搜索不区分大小写,咱们使用了 toLowerCase()
方法。
2. 高亮显示
高亮显示的关键在于,找到搜索结果中的关键词,然后用 <span>
标签包裹起来,并给它加上特定的样式。
<template>
<div>
<input type="text" v-model="searchText" placeholder="请输入关键词">
<ul>
<li v-for="(item, index) in filteredData" :key="index" v-html="highlightText(item.name)"></li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
searchText: '',
data: [
{ id: 1, name: 'Apple iPhone 13' },
{ id: 2, name: 'Samsung Galaxy S22' },
{ id: 3, name: 'Xiaomi 12 Pro' },
{ id: 4, name: 'OnePlus 10 Pro' },
],
};
},
computed: {
filteredData() {
if (!this.searchText) {
return this.data;
}
return this.data.filter(item =>
item.name.toLowerCase().includes(this.searchText.toLowerCase())
);
},
},
methods: {
highlightText(text) {
if (!this.searchText) {
return text;
}
const regex = new RegExp(this.searchText, 'gi');
return text.replace(regex, match => `<span class="highlight">${match}</span>`);
},
},
};
</script>
<style scoped>
.highlight {
background-color: yellow;
}
</style>
这里我们使用了一个 highlightText
方法,它接收一个文本字符串作为参数,然后使用正则表达式找到所有匹配的关键词,并用 <span class="highlight">
标签包裹起来。注意 v-html
指令的使用,它可以将 HTML 字符串渲染到页面上。
3. 搜索建议(自动补全)
搜索建议的实现方式通常是:在用户输入时,向后端发送请求,获取相关的搜索建议。为了避免用户频繁输入导致不必要的请求,咱们可以使用 lodash
的 debounce
函数进行防抖处理。
<template>
<div>
<input type="text" v-model="searchText" @input="handleInput" placeholder="请输入关键词">
<ul>
<li v-for="(suggestion, index) in suggestions" :key="index" @click="selectSuggestion(suggestion)">{{ suggestion }}</li>
</ul>
</div>
</template>
<script>
import debounce from 'lodash/debounce';
export default {
data() {
return {
searchText: '',
suggestions: [],
};
},
mounted() {
this.debouncedGetSuggestions = debounce(this.getSuggestions, 300);
},
methods: {
handleInput() {
this.debouncedGetSuggestions();
},
async getSuggestions() {
if (!this.searchText) {
this.suggestions = [];
return;
}
// 模拟后端请求
await new Promise(resolve => setTimeout(resolve, 500)); // 模拟网络延迟
const mockSuggestions = [
'Apple iPhone 13 Pro',
'Apple iPhone 13 Pro Max',
'Samsung Galaxy S22 Ultra',
'Samsung Galaxy S22 Plus',
'Xiaomi 12 Pro Global Version',
'Xiaomi 12 Pro Price',
];
this.suggestions = mockSuggestions.filter(suggestion =>
suggestion.toLowerCase().includes(this.searchText.toLowerCase())
);
},
selectSuggestion(suggestion) {
this.searchText = suggestion;
this.suggestions = [];
},
},
};
</script>
这段代码中,handleInput
方法会在用户输入时触发,然后调用 debouncedGetSuggestions
方法。debouncedGetSuggestions
方法是 getSuggestions
方法的防抖版本,它会在 300 毫秒内只执行一次。getSuggestions
方法会向后端发送请求,获取相关的搜索建议,并将结果更新到 suggestions
数组中。
4. 历史记录
历史记录的实现方式通常是将用户的搜索历史保存在 localStorage
中,然后在页面加载时读取出来。
<template>
<div>
<input type="text" v-model="searchText" @keyup.enter="addHistory" placeholder="请输入关键词">
<ul>
<li v-for="(history, index) in historyList" :key="index" @click="selectHistory(history)">{{ history }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
searchText: '',
historyList: [],
};
},
mounted() {
this.historyList = JSON.parse(localStorage.getItem('searchHistory') || '[]');
},
methods: {
addHistory() {
if (!this.searchText) {
return;
}
// 去重
if (this.historyList.includes(this.searchText)) {
return;
}
this.historyList.unshift(this.searchText); // 添加到数组头部
localStorage.setItem('searchHistory', JSON.stringify(this.historyList));
},
selectHistory(history) {
this.searchText = history;
},
},
};
</script>
这段代码中,addHistory
方法会在用户按下回车键时触发,它会将用户的搜索内容添加到 historyList
数组中,并保存到 localStorage
中。mounted
钩子函数会在页面加载时读取 localStorage
中的搜索历史。
第三部分:优化和扩展
以上只是最基本的功能实现,如果想要进一步提升用户体验,还可以进行以下优化和扩展:
- 服务端搜索: 如果数据量非常大,建议将搜索逻辑放在后端进行,可以提高搜索效率。
- 索引: 使用索引可以加快搜索速度,比如 ElasticSearch。
- 拼写纠错: 当用户输入错误的关键词时,可以提供拼写纠错功能。
- 热词推荐: 推荐当前热门的搜索关键词。
- 分类搜索: 允许用户按照不同的分类进行搜索。
表格总结:核心功能对比
功能 | 实现方式 | 优点 | 缺点 |
---|---|---|---|
模糊搜索 | String.prototype.includes() |
简单易用 | 性能较低,不适合大数据量 |
高亮显示 | 正则表达式 + v-html |
效果直观 | 需要注意 XSS 攻击 |
搜索建议 | 防抖函数 + 后端请求 | 体验好,减少不必要的请求 | 需要后端支持 |
历史记录 | localStorage |
简单易用 | 存储容量有限,只能保存少量数据 |
Vuex 集成(可选)
如果你的应用需要多个组件共享搜索历史,那么 Vuex 就派上用场了。
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
searchHistory: JSON.parse(localStorage.getItem('searchHistory') || '[]')
},
mutations: {
ADD_HISTORY (state, history) {
if (state.searchHistory.includes(history)) {
return;
}
state.searchHistory.unshift(history);
localStorage.setItem('searchHistory', JSON.stringify(state.searchHistory));
},
CLEAR_HISTORY (state) {
state.searchHistory = [];
localStorage.removeItem('searchHistory');
}
},
actions: {
addHistory ({ commit }, history) {
commit('ADD_HISTORY', history)
},
clearHistory ({ commit }) {
commit('CLEAR_HISTORY')
}
},
getters: {
searchHistory: state => state.searchHistory
}
})
然后在组件中使用:
<template>
<div>
<input type="text" v-model="searchText" @keyup.enter="addHistory" placeholder="请输入关键词">
<ul>
<li v-for="(history, index) in searchHistory" :key="index" @click="selectHistory(history)">{{ history }}</li>
</ul>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
data() {
return {
searchText: '',
};
},
computed: {
...mapGetters(['searchHistory'])
},
methods: {
...mapActions(['addHistory']),
selectHistory(history) {
this.searchText = history;
},
addHistory() {
if (!this.searchText) {
return;
}
this.addHistory(this.searchText);
}
},
};
</script>
结尾:总结与展望
今天咱们一起学习了 Vue 应用中搜索功能的实现方式,包括模糊搜索、高亮显示、搜索建议和历史记录。希望这些知识能够帮助你打造一个功能强大、体验优秀的搜索功能。
记住,技术是不断发展的,要保持学习的热情,不断探索新的技术,才能成为一名优秀的程序员! 下次有机会,咱们再聊聊如何使用 ElasticSearch 构建更强大的搜索功能! 祝大家编码愉快!