六、文章搜索
创建组件并配置路由
1、创建 src/views/search/index.vue
<template> <div class="search-container">搜索页面</div> </template>
<script> export default { name: "SearchPage", components: {}, props: {}, data() { return {}; }, computed: {}, watch: {}, created() {}, methods: {} }; </script>
<style scoped></style>
|
2、然后把搜索页面的路由配置到根组件路由(一级路由)
{ path: '/search', omponent: Search }
|
最后访问 /search
测试。
页面布局
1、创建 src/views/search/components/search-history.vue
<template> <div class="search-history"> <van-cell title="搜索历史"> <span>全部删除</span> <span>完成</span> <van-icon name="delete" /> </van-cell> <van-cell title="hello"> <van-icon name="close" /> </van-cell> <van-cell title="hello"> <van-icon name="close" /> </van-cell> <van-cell title="hello"> <van-icon name="close" /> </van-cell> <van-cell title="hello"> <van-icon name="close" /> </van-cell> </div> </template>
<script> export default { name: 'SearchHistory', components: {}, props: {}, data () { return {} }, computed: {}, watch: {}, created () {}, mounted () {}, methods: {} } </script>
<style scoped lang="less"></style>
|
2、创建 src/views/search/components/search-suggestion.vue
<template> <div class="search-suggestion"> <van-cell title="黑马程序员..." icon="search"></van-cell> <van-cell title="黑马程序员..." icon="search"></van-cell> <van-cell title="黑马程序员..." icon="search"></van-cell> <van-cell title="黑马程序员..." icon="search"></van-cell> <van-cell title="黑马程序员..." icon="search"></van-cell> </div> </template>
<script> export default { name: 'SearchSuggestion', components: {}, props: {}, data () { return {} }, computed: {}, watch: {}, created () {}, mounted () {}, methods: {} } </script>
<style scoped lang="less"></style>
|
3、创建 src/views/search/components/search-result.vue
<template> <div class="search-result"> <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" > <van-cell v-for="item in list" :key="item" :title="item" /> </van-list> </div> </template>
<script> export default { name: 'SearchResult', components: {}, props: {}, data () { return { list: [], loading: false, finished: false } }, computed: {}, watch: {}, created () {}, mounted () {}, methods: { onLoad () { setTimeout(() => { for (let i = 0; i < 10; i++) { this.list.push(this.list.length + 1) }
this.loading = false
if (this.list.length >= 40) { this.finished = true } }, 1000) } } } </script>
<style scoped lang="less"></style>
|
4、搜索组件内容如下:
<template> <div class="search-container">
<form action="/"> <van-search v-model="searchText" show-action placeholder="请输入搜索关键词" background="#3296fa" @search="onSearch" @cancel="onCancel" /> </form>
<search-history />
<search-suggestion />
<search-result /> </div> </template>
<script> import SearchHistory from './components/search-history' import SearchSuggestion from './components/search-suggestion' import SearchResult from './components/search-result'
export default { name: 'SearchIndex', components: { SearchHistory, SearchSuggestion, SearchResult }, props: {}, data () { return { searchText: '' } }, computed: {}, watch: {}, created () {}, mounted () {}, methods: { onSearch (val) { console.log(val) }, onCancel () { this.$router.back() } } } </script>
<style scoped lang="less"> .search-container { .van-search__action { color: #fff; } } </style>
|
处理页面显示状态
1、在 data
中添加数据用来控制搜索结果的显示状态
data () { ... isResultShow: false }
|
2、在模板中绑定条件渲染
<search-result v-if="isResultShow" />
<search-suggestion v-else-if="searchText" />
<search-history v-else />
|
搜索联想建议
基本思路:
- 当搜索框输入内容的时候,请求加载联想建议的数据
- 将请求得到的结果绑定到模板中
基本功能
一、将父组件中搜索框输入的内容传给联想建议子组件
二、在子组件中监视搜索框输入内容的变化,如果变化则请求获取联想建议数据
三、将获取到的联想建议数据展示到列表中
防抖优化
1、安装 lodash
2、防抖处理
import { debounce } from "lodash"
|
不建议下面这样使用,因为这样会加载整个模块。
import _ from 'lodash' _.debounce()
|
onSearchInput: debounce(async function () { const searchContent = this.searchContent if (!searchContent) { return }
const { data } = await getSuggestions(searchContent)
this.suggestions = data.data.options
}, 200),
|
搜索关键字高亮
如何将字符串中的指定字符在网页中高亮展示?
将需要高亮的字符包裹 HTML 标签,为其单独设置颜色。
"Hello <span style="color: red">World</span>"
|
在 Vue 中如何渲染带有 HTML 标签的字符串?
data () { return { htmlStr: 'Hello <span style="color: red">World</span>' } }
|
<div>{{ htmlStr }}</div> <div v-html="htmlStr"></div>
|
如何把字符串中指定字符统一替换为高亮(包裹了 HTML)的字符?
const str = "Hello World"
"Hello World".replace('Hello', '<span style="color: red">Hello</span>')
"Hello World Hello abc".replace('Hello', '<span style="color: red">Hello</span>')
"Hello World Hello abc".replace(/Hello/gi, '<span style="color: red">Hello</span>')
|
一个小扩展:使用字符串的 split 结合数组的 join 方法实现高亮
var str = "hello world 你好 hello";
const arr = str.split("hello");
arr.join("<span>hello</span>");
|
下面是具体的处理。
1、在 methods 中添加一个方法处理高亮
highlight (source, keyword) { const reg = new RegExp(keyword, 'gi') return source.replace(reg, `<span style="color: #3296fa">${keyword}</span>`) },
|
2、然后在联想建议列表项中绑定调用
<van-cell-group v-else-if="searchContent"> <van-cell icon="search" v-for="(item, index) in suggestions" :key="index" @click="onSearch(item)" > <div slot="title" v-html="highlight(item, searchContent)"></div> </van-cell> </van-cell-group>
|
搜索结果
思路:
一、获取搜索关键字
1、声明接收父组件中的搜索框输入的内容
props: { q: { type: String, require: true } },
|
2、在父组件给子组件传递数据
<search-result v-if="isResultShow" :q="searchText" />
|
最后在调试工具中查看确认是否接收到 props 数据。
二、请求获取数据
1、在 api/serach.js
添加封装获取搜索结果的请求方法
export function getSearch(params) { return request({ method: "GET", url: "/app/v1_0/search", params }) }
|
2、请求获取
+ import { getSearch } from '@/api/search'
export default { name: 'SearchResult', components: {}, props: { q: { type: String, require: true } }, data () { return { list: [], loading: false, finished: false, + page: 1, + perPage: 20 } }, computed: {}, watch: {}, created () {}, mounted () {}, methods: { +++ async onLoad () { const { data } = await getSearch({ page: this.page, per_page: this.perPage, q: this.q })
const { results } = data.data this.list.push(...results)
this.loading = false
if (results.length) { this.page++ } else { this.finished = true } } } }
|
三、最后,模板绑定
<van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" > <van-cell + v-for="(article, index) in list" + :key="index" + :title="article.title" /> </van-list>
|
搜索历史记录
添加历史记录
当发生搜索的时候我们才需要记录历史记录。
1、在 data 中添加一个数据用来存储历史记录
data () { return { ... searchHistories: [] } }
|
2、在触发搜索的时候,记录历史记录
onSearch (val) { this.searchText = val
const index = this.searchHistories.indexOf(val) if (index !== -1) { this.searchHistories.splice(index, 1) } this.searchHistories.unshift(val)
this.isResultShow = true },
|
展示历史记录
<van-cell-group v-else> <van-cell title="历史记录"> <van-icon name="delete" /> <span>全部删除</span> <span>完成</span> </van-cell> <van-cell :title="item" v-for="(item, index) in searchHistories" :key="index" > <van-icon name="close"></van-icon> </van-cell> </van-cell-group>
|
删除历史记录
基本思路:
- 给历史记录中的每一项注册点击事件
- 在处理函数中判断
- 如果是删除状态,则执行删除操作
- 如果是非删除状态,则执行搜索操作
一、处理删除相关元素的展示状态
1、在 data 中添加一个数据用来控制删除相关元素的显示状态
data () { return { ... isDeleteShow: false } }
|
2、绑定使用
<van-cell-group v-else> <van-cell title="历史记录"> <template v-if="isDeleteShow"> <span @click="searchHistories = []">全部删除</span> <span @click="isDeleteShow = false">完成</span> </template> <van-icon v-else name="delete" @click="isDeleteShow = true"></van-icon> </van-cell> <van-cell :title="item" v-for="(item, index) in searchHistories" :key="index" @click="onSearch(item)" > <van-icon v-show="isDeleteShow" name="close" @click="searchHistories.splice(index, 1)" ></van-icon> </van-cell> </van-cell-group>
|
二、处理删除操作
<van-cell-group v-else> <van-cell title="历史记录"> <template v-if="isDeleteShow"> + <span @click="searchHistories = []">全部删除</span> <span @click="isDeleteShow = false">完成</span> </template> <van-icon v-else name="delete" @click="isDeleteShow = true" /> </van-cell> <van-cell :title="item" v-for="(item, index) in searchHistories" :key="index" + @click="onHistoryClick(item, index)" > <van-icon v-show="isDeleteShow" name="close"></van-icon> </van-cell> </van-cell-group>
|
onHistoryClick (item, index) { if (this.isDeleteShow) { this.searchHistories.splice(index, 1) } else { this.onSearch(item) } }
|
数据持久化
1、利用 watch 监视统一存储数据
watch: { searchHistories (val) { setItem('serach-histories', val) } },
|
2、初始化的时候从本地存储获取数据
data () { return { ... searchHistories: getItem('serach-histories') || [], } }
|