The main functions to be implemented are as follows:

Information list, TAB page switch, article report, channel management, article details, reading memory, focus on function, like function, comment function, reply to comment, search function, login function, personal center, edit information, xiaozhi students…

Today to achieve the main function is: search function

inlayout/layout.vueIn the

0 to display my and unlogged functions according to whether the user is logged in

<van-tabbar route> <van-tabbar-item to="/" icon="home-o"> Icon ="chat-o"> q&A </van-tabbar-item> <van-tabbar-item to="/video" icon="video-o"> <van-tabbar-item  to="/user" icon="search"> + {{$store.state.tokenInfo.token ? }} </van-tabbar-item> </van-tabbar>Copy the code

1 Search Page

1.1newsrc/views/search/search.vuepage

<template> <div> </template> <script> export default {} </script> <style lang="less" scoped> </style>Copy the code

1.2 Supplementary Route Configuration

 
  const routes = [
  {
    path: '/login',
    name: 'login',
    component: Login
  },
  {
    path: '/',
    name: 'layout',
    component: Layout,
    // ....
  },
  {
+    path: '/search',
+    name: 'search',
+    component: () => import(/* webpackChunkName: "search" */ '../views/search/search.vue')
  }
]
Copy the code

1.3 Configuring Route Forward

insrc\views\layout\layout.vue, click the button to realize the route jump.

<! <van-nav-bar fixed >< div slot="left" class="logo"></div> <van-button slot="right" Class =" search-bTN "round type="info" size="small" icon="search" + @click="$router.push('/search')" > </van-nav-bar>Copy the code

1.4 Test directly in the address barhttp://localhost:8080/#/search

2 Search page – Component layout

2.1 Analysis Structure

From top to bottom, the page structure can be divided into four parts

  • The navigation area

  • Input area

    • Using the Search component
  • Intelligent prompt area. Lenovo suggested

    • Using the Cell Component
  • Search the history area

2.2 the layout

$router.back(

<template> <div> <! -- nav-bar this.$router.push() : $router.back() : Back button on ===== page --> <van-nav-bar title=" Search center "left-arrow @click-left="$router.back()"></van-nav-bar> <! --> <van-search v-model. Trim ="keyword" show-action placeholder=" placeholder "> <! -- #action ==== slot="action" --> <! - < template slot = "action" > < div > search < / div > < / template > -- > < div slot = "action" > search < / div > < / van - search > <! <van-cell group> <van-cell title=" cell "icon="search"/> <van-cell title=" cell" icon="search"/> <van-cell title=" cell "icon="search"/> <van-cell Title =" cell "icon="search"/> </van-cell > <! <van-cell title=" cell ">< van-cell name="close"></van-icon> </van-cell> <van-cell title=" cell ">< van-icon name="close"></van-icon> </van-cell> </van-cell> </div> </template> <script> export default { name: 'Search', data () { return { keyword: '' } } } </script>Copy the code

2.3 Effect as shown in figure

3 Search page – associative suggestion function

When users write content in the input box, lenovo suggestions are displayed at the bottom of the input box

3.1 packaging API

createapi/search.jsAnd write

Import request from '.. /utils/request' /** * Get search suggestion * @param {*} keyword Search keyword * @returns */ export const getSuggestion = (keyword) => {return  request({ url: 'v1_0/suggestion', method: 'GET', params: { q: keyword } }) }Copy the code

3.2 Request for data when the search content changes

<! <van-search + @input="hInput" v-model. Trim ="keyword" show-action placeholder=" placeholder "> <van-search + @input="hInput" v-model.Copy the code
import { getSuggestion } from '@/api/search.js'
Copy the code
Return {keyword: ", + suggestions: [] // suggestions}Copy the code
Async hInput () {console.log(this.keyword) // If the user does not enter anything, the suggestion is cleared. If (this.keyword === ") {this.suggestions = [] return} try {const {data: { data } } = await getSuggestion(this.keyword) this.suggestions = data.options } catch (err) { console.log(err) } },Copy the code

3.3 Data Rendering

<! -- 2. Search Suggestions Based on the keywords you type above, The backend returns suggestions --> <van-cell-group> <van-cell V -for="(suggestion,idx) in suggestions" :key="idx" :title="suggestion" icon="search" /> </van-cell-group>Copy the code

4 Search page – Highlight search keywords

Since the original data will be used in subsequent operations, it is not possible to modify the original data directly, but to create a copy

Use a calculated property to hold the highlighted suggestion.

  • In the calculation of attributes, the original data should be processed: replace the content with a string of re +replace to achieve the goal of highlighting.

  • Display data in V-HTML.

4.1 Encapsulating auxiliary highlighting functions

// Source string, Export const heightLight = (STR, key) => {const reg = new RegExp(key, 'ig') return str.replace(reg, (val) => { return `<span style="color:red">${val}</span>` }) }Copy the code

4.2 Adding Computing Attributes

computed: {cSuggestions () {// each item in the suggestions go to replace // each item in the suggestions ====> heightLight(each item in the suggestions, this.keyword) return this.suggestions.map(item => { return heightLight(item, this.keyword) }) } },Copy the code

4.3 apply colours to a drawing

<! -- 2. Search Suggestions Based on the keywords you type above, The back end returns suggestions --> <van-cell-group> <van-cell V-for ="(item, IDX) in cSuggestions" :key=" IDX "icon="search"> <div v-html="item"></div> </van-cell> </van-cell-group>Copy the code

4.4 Viewing the Effect

5 Search page – Displays search history

After the user searches for a certain keyword, it is recorded for later rapid search

1. Format and location for saving records

Format: array. For example: [‘a’,’ phone ‘,’javascript’]

2. Records should be kept under two circumstances:

  1. Save when you click search on the search box

  2. Save when you click on the associative suggestion given by the system

5.1 Search Page – Add search records

Data () {return {keyword: "' + historys: [' tianjin ', '1'], Suggestions: []}},Copy the code
<! <van-cell title=" history "></van-cell> <van-cell v-for="(item, IDx) in historys" :key="idx" :title="item"> <van-icon name="close" /> </van-cell> </van-cell-group> <! -- / Search history -->Copy the code

Encapsulates methods to add history for later invocation

AddHistory (STR) {this.historys.push(STR) // todo:},Copy the code

5.2 Click Lenovo Suggestion

<van-cell-group>
  <van-cell
      v-for="(item,idx) in cSuggestions"
      :key="idx"
      icon="search"
+     @click="hClickSuggetion(idx)">
    <div v-html="item"></div>
  </van-cell>
</van-cell-group>
Copy the code
// Case 2: A user clicked the search suggestion hclicktion (idx) {// 1. Add a history this.addHistory(this.suggestions[idx]) // 2. Jump to search results page}Copy the code

5.3 When clicking the search button

<div slot="action" @click="hSearch">Copy the code
// Case 1: the user clicked on the search hSearch () {// 1. This.addhistory (this.keyword) // 2. Jump to search results page // todo},Copy the code

5.4 Checking whether Bound events Take effect

Figure slightly

5.5 Search Page – Optimized the way to add history

Improve the function of adding history records

When adding historical records, note the following:

  • There can be no duplicates
  • The afterjoin is placed at the top of the array
AddHistory (STR) {// if (STR) {// if (STR) {// if (STR) { Const idx = this.history.findIndex(item => item === STR) // idx! == -1 && this.historys.splice(idx, 1) if (idx > -1) { this.history.splice(idx, This.history. unshift(STR)}Copy the code

6 Search page – Delete history

Provide users with the function of deleting history records: there is a close button behind each record, click this button can delete this record

6.1 Add click events to the X icon

<! <van-cell title=" history "></van-cell> <van-cell v-for="(item, IDx) in historys" :key="idx" :title="item"> + <van-icon name="close" @click="hDelHistory(idx)"/> </van-cell> </van-cell-group> <! -- / Search history -->Copy the code
HDelHistory (idx) {this.historys.splice(idx, 1)}Copy the code

6.2 Search Page – Persistent search history

Save history records to localStorage

  • Encapsulate a module for persisting history (set, delete)
  • Save once when searching for history changes (add, remove)
  • Use import local data initially (fetch data from localStorage)

6.2.1 createutils/storageHistory.js

// Eliminate magic string const HISTORY_STR = 'HistoryInfo' export const getHistory = () => {return JSON.parse(localStorage.getItem(HISTORY_STR)) } export const setHistory = HistoryInfo => { localStorage.setItem(HISTORY_STR, JSON.stringify(HistoryInfo)) } export const removeHistory = () => { localStorage.removeItem(HISTORY_STR) }Copy the code

6.2.2 Introduction and Use

`import { setHistory, getHistory } from '@/utils/storageHistory.js'`
Copy the code
Data () {return {keyword: '', // use [] historys: GetHistory () | | [], / / save history [' regular ', 'javascript'] Suggestions: [] / / the current search Suggestions}}Copy the code
// Add a history item // 1. No duplicates // 2. After adding, put it at the top of array // 3. AddHistory (STR) {// (1) Const idx = this.history.findIndex(item => item === STR) if (idx > -1) {this.historys. This.historys.unshift (STR) // (3) persistent + setHistory(this.history)}, HDelHistory (idx) {this.historys.splice(idx, 1) // Persistent + setHistory(this.history)}Copy the code

6.3 Search page – Displays association suggestions and history records

Associative suggestion and search history are mutually exclusive:

  • If you are currently searching for content, the search history is not displayed, but the association suggestions are displayed.
  • If the current search content is not displayed, the search history is displayed and the association suggestion is not displayed.
<! -- Lenovo recommends V-HTML to display HTML string effects normally --> <! Based on the keywords you type above, the back end will return suggestions V-if ="suggestion.length" : if there are search suggestions --> <van-cell-group v-if="suggestion.length" >... </van-cell-group> <! -- / Lenovo suggestion --> <! -- search history --> <van-cell-group v-else>... </van-cell-group> <! -- / Search history -->Copy the code

Anti – shake and throttling function

A character change in the input field immediately sends a request for search suggestions.

  • For the user, the search suggestions will come in time, but during the search process, the words you type are not finished, and the suggestions you get are mostly useless
  • The frequency with which this interface is called is too high for the server to be burdened.

7.1 Achieving the anti-shake function

HInput () {clearTimeout(this.timer) console.log(this.keyword) this.timer = setTimeout(() => {clearTimeout(this.timer) console.log(this.keyword) this.timer = setTimeout(() => { this.doAjax() }, 200) }, async doAjax () { if (this.keyword === '') { this.suggestions = [] return } try { const res = await getSuggestion(this.keyword) // console.log(res) this.suggestions = res.data.data.options } catch (err) { console.log(err) } },Copy the code

7.2 Enabling throttling

// throttle hInput () {const dt = date.now () // Get the current timestamp ms if (dt-this.startTime > 500) {this.doajax () this.startTime = Dt} else {console.log(' current timestamp is ', dt, 'less than 500ms since last execution, so not executed ')}}, async doAjax () { if (this.keyword === '') { this.suggestions = [] return } try { const res = await getSuggestion(this.keyword) // console.log(res) this.suggestions = res.data.data.options } catch (err) { console.log(err) } }Copy the code

7.3 Throttling and anti-shake only need to be selected

8 Search Results

Search results are displayed on a separate page:

  • Route forward and pass in the keyword you want to search for
  • Upon receipt of the keyword, tune the interface
  • Retrieves the query results and displays them.

8.1 Creating Components

views/search/result.vue

<template> <div class="serach-result"> <! --> <van-nav-bar title=" XXX search result "left-arrow fixed @click-left="$router.back()" /> <! -- / navigation bar --> <! <van-list class="article-list" v-model="loading" :finished="finished" complete-text =" no more "@load="onLoad" >  <van-cell v-for="item in list" :key="item" :title="item" /> </van-list> <! Export default {name: 'SearchResult', data () {return {list: [], loading: False, finished: false}}, 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 } }, 500) } } } </script> <style lang="less" scoped> .serach-result { height: 100%; overflow: auto; .article-list { margin-top: 39px; } } </style>Copy the code

8.2 Creating a Route

{ path: '/searchResult', name: 'searchResult', component: () => import('.. /views/search/searchResult.vue') },Copy the code

8.3 Sending Parameters through a Route and Switching to the Page

HSearch () {if (this.keyword === "") {return} // 1. This.addhistory (this.keyword) // 2. + this.$router. Push ('/search/result? keyword=' + this.keyword) }Copy the code
<! --> <van-cell group v-else> <van-cell title=" history" /> <van-cell v-for="(item,idx) in history" :key="idx" :title="item" + @click="$router.push('/search/result? keyword=' + item)"> <van-icon name="close" @click.stop="hDelHistory(idx)"></van-icon> </van-cell> </van-cell-group>Copy the code
// Case 3: A user clicked the search suggestion hclicktion (idx) {// 1. Add a history this.addHistory(this.suggestion[idx]) // 2. + this.$router. Push ('/search/result? keyword=' + this.suggestions[idx]) }Copy the code

9 Search results – Obtain and display the search results

search/result.vueIn this.$route.query.keyword, we can get the query keyword passed in

created () {
    var keyword = this.$route.query.keyword
    alert(keyword)
}
Copy the code

9.1 Encapsulating Interfaces

inapi/serach.jsEncapsulating request method

@param {*} page page */ export const getSearchResult = (keyword, page) => { return request({ method: 'GET', url: 'v1_0/search', params: { q: keyword, page: page } }) }Copy the code

9.2 Invoking an Interface to Obtain Data

import { getSearchResult } from '@/api/search.js' export default { name: 'SearchResult', data () { return { list: [], Page: 1, // Loading: false, finished: false } } // --- async onLoad () { console.log(this.$route.query.keyword) // 1. Const res = await getSearchResult(this.$route.query.keyword, this.page) const arr = res.data.data.results // 2. When the data comes back, populate the list this.list.push(... This. Loading = false // 4. This. Finished =! Arr. length // 5. Page +1 this.page++}Copy the code

9.3 Data Rendering

<template> <div class="serach-result"> <! <van-nav-bar :title=" '${$route.query.keyword} "left-arrow fixed @click-left="$route.back ()" /> <! -- / navigation bar --> <! <van-list class="article-list" v-model="loading" :finished="finished" complete-text =" no more "@load="onLoad" >  <van-cell v-for="item in list" @click="$router.push('/article/' + item.art_id)" :key="item.art_id" :title="item.title" /> </van-list> <! </div> </template>Copy the code

9.4 Viewing The Effect