搜索联想建议

在这里插入图片描述

1. 基本思路:

当搜索框输入内容的时候,请求加载联想建议的数据
将请求得到的结果绑定到模板中

2. 基本功能

一、将父组件中搜索框输入的内容传给联想建议子组件
在这里插入图片描述

二、在子组件中监视搜索框输入内容的变化,如果变化则请求获取联想建议数据

在这里插入图片描述

三、将获取到的联想建议数据展示到列表中
在这里插入图片描述
父组件完整代码:

<template>
  <div class="search-container">
    <!--搜索栏-->
    <form action="/">
      <van-search v-model="searchText"  @search="onSearch"
                  @focus="isResultShow = false" @cancel="onCancel" show-action placeholder="请输入搜索关键词" />
    </form>
    <!--搜索结果-->
    <search-results v-if="isResultShow" />
    <!--联想建议-->
    <search-suggestion v-else-if="searchText" :search-text="searchText"/>
    <!--历史记录-->
    <search-history v-else />
  </div>
</template>

<script>
import SearchSuggestion from './components/search-suggestion.vue'
import SearchHistory from './components/search-history.vue'
import SearchResults from './components/search-results.vue'
export default {
  name: 'SearchIndex',
  data () {
    return {
      searchText: '', // 输入搜索框的内容
      isResultShow: false // 控制搜索结果的显示状态
    }
  },
  components: {
    SearchSuggestion,
    SearchHistory,
    SearchResults
  },
  methods: {
    onSearch (val) {
      // 展示搜索结果
      this.isResultShow = true
    },
    onCancel () {
      this.$router.back()
    }
  }
}
</script>

<style scoped>

</style>

子组件完整代码:

<template>
    <div class="search-suggestion">
      <van-cell v-for="(str, index) in suggestions"
                :key="index" icon="search" :title="str"></van-cell>
    </div>
</template>
<script>
import { getSearchSuggestions } from '../../../api/search.js'
import { debounce } from 'lodash'
// /*// 函数防抖
// const fn = _.debounce(function () {
//   console.log('hello')
// }, 1000)
//
// fn()
// fn()
// setTimeout(() => {
//   fn()
// }, 1200)
// fn()*/
export default {
  name: 'SearchSuggestion',
  data () {
    return {
      suggestions: [] // 联想建议数据列表
    }
  },
  props: {
    searchText: {
      type: String,
      required: true
    }
  },
  watch: {
    // 属性名:要监视的数据的名称
    // searchText () {
    //   console.log('je')
    // }
    // 监视的完整写法
    searchText: {
      // 当数据发生变化则会执行 handler处理函数
      handler: debounce(async function () {
        // 发请求
        const { data } = await getSearchSuggestions(this.searchText)
        this.suggestions = data.data.options
      }, 200),
      // async handler () {
      //   // 发请求
      //   const { data } = await getSearchSuggestions(this.searchText)
      //   this.suggestions = data.data.options
      // },
      immediate: true // 该回调将会在侦听开始之后被立即调用
    }
  }
}
</script>

<style scoped>

</style>

3. 防抖优化

loadsh官网
https://www.lodashjs.com/docs/lodash.debounce
在这里插入图片描述

1、安装 lodash

# yarn add lodash
npm i lodash

2、防抖处理

// lodash 支持按需加载,有利于打包结果优化
import { debounce } from "lodash"

不建议下面这样使用,因为这样会加载整个模块。

import _ from 'lodash'
_.debounce()
// debounce 函数
// 参数1:函数
// 参数2:防抖时间
// 返回值:防抖之后的函数,和参数1功能是一样的
onSearchInput: debounce(async function () {
  const searchContent = this.searchContent
  if (!searchContent) {
    return
  }

  // 1. 请求获取数据
  const { data } = await getSuggestions(searchContent)

  // 2. 将数据添加到组件实例中
  this.suggestions = data.data.options

  // 3. 模板绑定
}, 200),

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

联想建议优化——高亮搜索关键字

在这里插入图片描述

如何将字符串中的指定字符在网页中高亮展示?

"Hello World";

将需要高亮的字符包裹 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"

// 结果:<span style="color: red">Hello</span> World
"Hello World".replace('Hello', '<span style="color: red">Hello</span>')

// 需要注意的是,replace 方法的字符串匹配只能替换第1个满足的字符
// <span style="color: red">Hello</span> World Hello abc
"Hello World Hello abc".replace('Hello', '<span style="color: red">Hello</span>')

// 如果想要全文替换,使用正则表达式
// g 全局
// i 忽略大小写
// <span style="color: red">Hello</span> World <span style="color: red">Hello</span> abc
"Hello World Hello abc".replace(/Hello/gi, '<span style="color: red">Hello</span>')

一个小扩展:使用字符串的 split 结合数组的 join 方法实现高亮

var str = "hello world 你好 hello";

// ["", " world 你好 ", ""]
const arr = str.split("hello");

// "<span>hello</span> world 你好 <span>hello</span>"
arr.join("<span>hello</span>");

在这里插入图片描述

下面是具体的处理。

1、在 methods 中添加一个方法处理高亮

// 参数 source: 原始字符串
// 参数 keyword: 需要高亮的关键词
// 返回值:替换之后的高亮字符串
highlight (source, keyword) {
  // /searchContent/ 正则表达式中的一切内容都会当做字符串使用
  // 这里可以 new RegExp 方式根据字符串创建一个正则表达式
  // RegExp 是原生 JavaScript 的内置构造函数
  // 参数1:字符串,注意,这里不要加 //
  // 参数2:匹配模式,g 全局,i 忽略大小写
  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>
<!-- /联想建议 -->

在这里插入图片描述
完整代码:

<template>
    <div class="search-suggestion">
      <van-cell v-for="(str, index) in suggestions"
                :key="index" icon="search" >
        <div slot="title" v-html="hightlight(str)"></div>
      </van-cell>
    </div>
</template>
<script>
import { getSearchSuggestions } from '../../../api/search.js'
import { debounce } from 'lodash'
// /*// 函数防抖
// const fn = _.debounce(function () {
//   console.log('hello')
// }, 1000)
//
// fn()
// fn()
// setTimeout(() => {
//   fn()
// }, 1200)
// fn()*/
export default {
  name: 'SearchSuggestion',
  data () {
    return {
      suggestions: [] // 联想建议数据列表
    }
  },
  props: {
    searchText: {
      type: String,
      required: true
    }
  },
  watch: {
    // 属性名:要监视的数据的名称
    // searchText () {
    //   console.log('je')
    // }
    // 监视的完整写法
    searchText: {
      // 当数据发生变化则会执行 handler处理函数
      handler: debounce(async function () {
        // 发请求
        const { data } = await getSearchSuggestions(this.searchText)
        this.suggestions = data.data.options
      }, 200),
      // async handler () {
      //   // 发请求
      //   const { data } = await getSearchSuggestions(this.searchText)
      //   this.suggestions = data.data.options
      // },
      immediate: true // 该回调将会在侦听开始之后被立即调用
    }
  },
  methods: {
    hightlight (str) {
      // RegExp()是正则表达式的构造函数
      // 参数1: 字符串
      // 参数2: 匹配模式
      // 返回值: 正则对象
      const regStr = new RegExp(this.searchText, 'gi')
      return str.replace(regStr, `<span style="color: red">${this.searchText}</span>`)
    }
  }
}
</script>

<style scoped>

</style>

Logo

前往低代码交流专区

更多推荐