Dark horse headline project - day8 - search module - pull-up function, history, Lenovo search

History function

Objective: to realize the function of searching history

  • Initialize history data
data () {
    return {
        // Search keywords
        q: '',
        // Historical keywords
        history: JSON.parse(localStorage.getItem('keywords') || '[]')
    }
},
  • The history is displayed only when there is data
<div class="history-box" v-else-if="history.length">
  • Render history data
<van-cell v-for="(item, index) in history" :key="index">
  <a class="word_btn">{{item}}</a>
  <van-icon @click="delHistory(key)" class="close_btn" slot="right-icon" name="cross"/>
</van-cell>

Summary:

  1. Cache historical keywords after carriage return
  2. Enter the search component and directly read the cache when initializing the data
  3. Dynamic rendering history data
  • Array de duplication operation
handleSearch () {
    // After the carriage return is triggered: 1. Save the historical keyword; 2. Jump to search list page
    this.history.unshift(this.q)
    // Set is a constructor introduced by ES6. The storage structure is similar to that of array, in which duplicate data is not allowed
    this.history = [...new Set(this.history)]
    // Put the history array into the cache
    localStorage.setItem('keywords', JSON.stringify(this.history))
}

Summary: it is convenient to provide Set constructor based on ES6 for de duplication

Note: Set is a constructor introduced by ES6. The storage structure is similar to that of array, in which duplicate data is not allowed

  • Delete history
deleteSingle (index) {
  // Click the cross to delete the corresponding historical keyword
  this.history.splice(index, 1)
  // The cache should also be updated
  window.localStorage.setItem(SEARCHKEY, JSON.stringify(this.history))
},
  • Clear history
<van-icon name="delete" @click="deleteAll"></van-icon>
deleteAll () {
  // Clear all historical keywords
  this.history = []
  // The cache should also be emptied
  window.localStorage.removeItem('keywords')
},

Note: two parts should be deleted when deleting: 1. Data in data; 2. Data in cache

Associative search function

Objective: to realize the association search function

  • Encapsulated search interface method
export const searchList = (q) => {
  return request({
    method: 'get',
    url: 'v1_0/suggestion',
    params: {
      q
    }
  })
}
<van-search @input='keywordList' 
// Associative query
async keywordList () {
  const ret = await searchList(this.q)
  this.keylist = ret.data.options
},

Summary: enter a keyword and call the interface once to get the list data matching the keyword.

  • Realize function anti shake effect debounce / throttle (throttling)

Function anti shake function: limit the frequency of task execution

If the trigger interval of this condition is less than a fixed time, the task will be triggered twice.

Trigger condition: enter a character

Specified time: 1 second

Task: call interface to send request

// Associative query
keywordList () {
    // The following expression is function anti shake
    clearTimeout(this.timer)
    if (!this.q.trim()) return
    this.timer = setTimeout(async () => {
        const ret = await searchList(this.q)
        this.keylist = ret.data.options
    }, 1000)
},

Summary:

  1. Function anti shake debounce: the task will not be executed until the trigger condition exceeds a specific time for two consecutive times. (keyword search, account repeatability verification)
  2. Function throttling: execute the task only once in a fixed time, no matter how many times the condition is triggered. (paging dynamic loading)
  • Render search list results
<van-cell :key='index' v-for='(item, index) in keylist' icon="search">
  <p v-html='item'></p>
</van-cell>

Note: the v-html instruction is required to display the content

  • Highlight control of association list
// Requirement: highlight the content of the list item after matching with the key (wrap a layer of span label)
  this.keylist = ret.data.options.map(item => {
    // const arr = []
    // const arr = new Array()
    // const obj = {}
    // const obj = new Object()
    // const reg = /\d/
    // const reg = new RegExp('\d')
    // The native js method replace is used to replace substrings in the entire string
    const reg = new RegExp(this.q, 'ig')
    return item.replace(reg, `<span>${this.q}</span>`)
  })

Summary: be familiar with the usage of regular expression based constructor and js replace method.

  • Route jump is another way to pass parameters

Summary: when jumping to route through programmed navigation, you can go through the? After splicing the parameters to the routing path

this.$router.push('/sresult?kw=' + this.q)
// Route mapping
{
    path: '/sresult',
    component: Sresult
}

How to get the parameters after the question mark inside the component? this.$route.query.kw

this.$router.push('/sresult/' + this.q)
// Route mapping
{
    path: '/sresult/:kw',
    component: Sresult
}

The way to obtain this routing parameter inside the component: this$ route. params. kw

  • Realize the jump of search page
    • Jump after entering. The parameter is the entered keyword
// Implement search
handleSearch () {
  // Prevent entering empty strings
  // q.trim() is a native js method used to remove the space '' on both sides
  if (!this.q.trim()) return
  // After the carriage return is triggered: 1. Save the historical keyword; 2. Jump to search list page
  this.history.unshift(this.q)
  // Set is a constructor introduced by ES6. The storage structure is similar to that of array, in which duplicate data is not allowed
  this.history = [...new Set(this.history)]
  // Put the history array into the cache
  window.localStorage.setItem('keywords', JSON.stringify(this.history))
  // Jump to search list page
  // this.$router.push('/sresult?kw=' + this.q)
  // this.$router.push('/sresult/' + this.q)
  this.$router.push({
    // path: 'sresult',
    name: 'myresult',
    query: {
      kw: this.q
    }
  })
}

Summary:

  1. There are many kinds of jumps in programming navigation usage
  2. The name attribute can be set in the routing map, and the programmed navigation can jump based on the name value
  3. Different parameter transfer methods have different attributes of query/params
  • Click the list item of Lenovo to jump, and the parameter is the content of the list item
// Click Lenovo entry to jump
handleJump (kw) {
  // kw now includes the highlighted label of span, which needs to be removed
  const reg = new RegExp(`<span>${this.q}</span>`, 'ig')
  kw = kw.replace(reg, this.q)
  this.$router.push({
    name: 'myresult',
    query: {
      kw: kw
    }
  })
},

Summary: before clicking jump, the highlighted label of span needs to be removed from the parameters passed.

Search results - basic layout

Objective: to achieve the basic layout of the search list page

  • Search list layout
<div class="container">
  <!-- Navigation fixed positioning fixed -->
  <van-nav-bar fixed title="search result" left-arrow @click-left="$router.back()" />
  <!-- Article list -->
  <van-list v-model="loading" :finished="finished" finished-text="No more">
    <van-cell-group>
      <van-cell>
        <div class="article_item">
          <h3 class="van-ellipsis">PullRefresh Pull down refresh PullRefresh Drop-down refresh drop-down refresh</h3>
          <div class="img_box">
            <van-image class="w33" fit="cover" src="https://img.yzcdn.cn/vant/cat.jpeg" />
            <van-image class="w33" fit="cover" src="https://img.yzcdn.cn/vant/cat.jpeg" />
            <van-image class="w33" fit="cover" src="https://img.yzcdn.cn/vant/cat.jpeg" />
          </div>
          <div class="img_box">
            <van-image class="w100" fit="cover" src="https://img.yzcdn.cn/vant/cat.jpeg" />
          </div>
          <div class="info_box">
            <span>You are like a gust of wind</span>
            <span>8 comment</span>
            <span>10 Minutes ago</span>
          </div>
        </div>
      </van-cell>
    </van-cell-group>
  </van-list>
</div>
  • Search results list style
.container {
  padding-top: 92px;
  height: 100%;
  overflow-y: auto;
  box-sizing: border-box;
}
.article_item {
  h3 {
    font-weight: normal;
    line-height: 2;
  }
  .img_box {
    display: flex;
    justify-content: space-between;
    .w33 {
      width: 33%;
      height: 180px;
    }
    .w100 {
      height: 360px;
      width: 100%;
    }
  }
  .info_box {
    color: #999;
    line-height: 2;
    position: relative;
    span {
      padding-right: 20px;
    }
  }
}

Search results - pull up function

Objective: to realize the search pull-up function

  • Package pull-up loading interface
// Search the list of articles by keyword
export const searchArticles = (options) => {
  return request({
    method: 'get',
    url: 'v1_0/search',
    // axios uses params to pass get request parameters
    params: {
      // Current page number
      page: options.pagenum,
      // Number of entries per page
      per_page: options.pagesize,
      // Keywords for query
      q: options.kw
    }
  })
}
  • List related data
data () {
  return {
    loading: false,
    finished: false,
    // Search parameters
    queryData: {
      page: 1,
      perPage: 10,
      // Initialize data through routing parameters
      q: this.$route.query.q
    },
    // search result
    list: [],
    // Total list
    total: 0
  }
},
    
methods: {
  async searchArticles () {
    // Search article list results by keyword
    const [err, ret] = await searchArticles(this.queryData)
    if (err) {
      this.$toast.fail('Failed to query article')
    } else {
      // Get the list data and total number of articles
      this.list = ret.data.results
      this.total = ret.data.total_count
    }
  }
},
  • Trigger pull-up to load more actions
  methods: {
    async onLoad () {
      // When the page is loaded, it is triggered once. If there is not enough screen, it is called again
      const ret = await searchArticles(this.queryData)
      this.list.push(...ret.data.results)
      this.total = ret.data.total_count
      // End this loading
      this.loading = false
      // Judge the status of loading completion
      if (this.list.length >= this.total) {
        // No more data to load
        this.finished = true
      } else {
        // There is more data to load: page number accumulation
        this.queryData.pagenum += 1
      }
    }
  },
  created () {
    // Get query keywords in routing parameters
    this.queryData.kw = this.$route.query.kw
  }
  • Render list content
<van-cell v-for='item in list' :key='item.art_id.toString()'>
  <div class="article_item">
    <h3 class="van-ellipsis">{{item.title}}</h3>
    <div class="img_box">
      <van-image :key='index' v-for='(img, index) in item.cover.images' :class="[{w33: item.cover.type===3}, {w100: item.cover.type===1}]" fit="cover" :src="img" />
    </div>
    <div class="info_box">
      <span>{{item.aut_name}}</span>
      <span>{{item.comm_count}}comment</span>
      <span>{{item.pubdate|formatTime}}</span>
    </div>
  </div>
</van-cell>

Summary:

  1. Paging logic based on pagenum and pagesize
  2. Basic use of van list component
  3. Usage of dynamic binding of class name

summary

  • Historical keyword of cache search: local storage API
  • Array de duplication: a new constructor Set introduced based on ES6
  • Delete history Keywords: single delete and delete all (local storage API)
  • Prevent entering null characters: the usage of trim method of native js
  • Business process of function anti shake (※); Contrast function throttling
    • Concept; Application scenarios; code implementation
  • Basic functions of keyword matching: calling interface; Fill page
  • Highlight control of list items: regular constructor usage (benefit: support variables) (※)
  • Usage of route passing parameters (passing parameters based on question mark) (※)
  • Program navigation route jump. Route mapping supports name, or jump with name (※)
    • Note the parameter passed: query/params
    • Usage of name
  • Paging based on pagenum and pagesize parameters: time-based paging

Keywords: Front-end ECMAScript Vue

Added by bufhal on Sun, 30 Jan 2022 03:23:57 +0200