最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3指令之搜索框輸入防抖功能實(shí)現(xiàn)

 更新時(shí)間:2022年12月29日 11:20:54   作者:Lvzl  
在Vue開發(fā)中遇到了搜索框輸入防抖處理,算是防抖的使用場(chǎng)景之一吧,這篇文章主要給大家介紹了關(guān)于Vue3指令之搜索框輸入防抖功能實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下

前言

「搜索??」這個(gè)場(chǎng)景在各種業(yè)務(wù)的系統(tǒng)中都是是非常常見的,比如電商平臺(tái)的商品搜索、百度搜索、掘金搜索、google搜索......,只要是有內(nèi)容呈現(xiàn)給用戶的,都少不了搜索功能。

按照觸發(fā)搜索動(dòng)作的不同可分為:

  • 輸完關(guān)鍵字后手動(dòng)觸發(fā)搜索
  • 輸入字符自動(dòng)搜索

第一種是由用戶去決定何時(shí)進(jìn)行搜索,沒啥問題。

第二種是通過監(jiān)聽用戶錄入的事件自動(dòng)搜索,自動(dòng)搜索能在一定程度上提升用戶體驗(yàn)(比如在用戶輸入時(shí)關(guān)鍵詞聯(lián)想提示),同時(shí)也可能會(huì)帶來問題,因?yàn)?code>input事件觸發(fā)是非常頻繁的,比如下面這個(gè)示例:

打開百度的搜索,找到輸入框的dom,然后綁定一個(gè)input事件,看看我們錄入一個(gè)telephone會(huì)觸發(fā)多少次input事件:

temp1.addEventListener('oninput', (val) => console.log(val))

觸發(fā)了10次:

那如果每觸發(fā)一次都會(huì)調(diào)用后臺(tái)接口查詢,那當(dāng)用戶量足夠大,就會(huì)給后臺(tái)服務(wù)器帶來很大的壓力,導(dǎo)致接口響應(yīng)慢,甚至引起服務(wù)器宕機(jī),也會(huì)給用戶帶來不好的體驗(yàn)。

為了不引起過多請(qǐng)求給服務(wù)端造成壓力,我們期望在用戶在輸入完以后再發(fā)起請(qǐng)求,那怎么判斷用戶是否輸入完了?

可以認(rèn)為當(dāng)用戶在一個(gè)固定的時(shí)間內(nèi)都沒有錄入字符是輸入完成/暫時(shí)輸入完成。這個(gè)是老生常談的知識(shí)點(diǎn)了————「防抖」和「節(jié)流」。掘金有很多文章專門寫這個(gè)的,筆者在此不過多描述,簡(jiǎn)單一筆帶過說下筆者的看法。

防抖 & 節(jié)流

防抖

防抖的函數(shù)在調(diào)用后,如果在防抖時(shí)間內(nèi)沒有再次觸發(fā),就會(huì)在過了 防抖時(shí)間 后執(zhí)行;如果在防抖時(shí)間內(nèi)再次觸發(fā),不論觸發(fā)多少次,執(zhí)行的時(shí)機(jī)會(huì)一直往后延遲,直到滿足最后一次調(diào)用時(shí)間 小于 當(dāng)前時(shí)間減去防抖時(shí)間才會(huì)執(zhí)行。

function debounce(fn, time) {
  let timer
  return function (...argu) {
    if (timer) {
      clearTimeout(timer)
      timer = null
    }
    timer = setTimeout(() => {
      fn(...argu)
      clearTimeout(timer)
      timer = null
    }, time)
  }
}

節(jié)流

節(jié)流函數(shù)在調(diào)用后,在設(shè)置的節(jié)流時(shí)間后執(zhí)行一次,在此期間,不論觸發(fā)多少次,都直接return了。

function throttle(fn, time) {
  let flag = true
  return function (...argu) {
    if (!flag) {
      return
    }
    flag = false
    let timer = setTimeout(() => {
      fn(...argu)
      flag = true
      clearTimeout(timer)
      timer = null
    }, time)
  }
}

再來看下加了防抖 & 節(jié)流 處理的input事件執(zhí)行情況:

  • 防抖:

  • 防抖 + 節(jié)流:

從上面的兩個(gè)圖不難看出防抖 和節(jié)流的區(qū)別,節(jié)流的函數(shù)如果一直被觸發(fā),每隔一段時(shí)間執(zhí)行一次。而防抖則是一直延遲,最后執(zhí)行一次。

輸入防抖存在的問題

上面的防抖函數(shù)執(zhí)行貌似沒啥問題,前提是我們輸入的是英文,如果是中文輸入就出問題了,看下圖:

當(dāng)中文輸入的時(shí)候,即使已經(jīng)防抖處理了,還可能會(huì)執(zhí)行多次。接下來咱們進(jìn)入正題了,如何實(shí)現(xiàn)輸入防抖Vue3指令(并解決中文輸入觸發(fā)多次的問題)。

指令實(shí)現(xiàn)

為什么要以指令的方式實(shí)現(xiàn)?我能想到的有以下兩點(diǎn):

  • 將防抖處理的邏輯封裝在指令內(nèi)部重用,更易用。
  • 指令要支持input輸入框,也要支持封裝input的組件,也就是說需要進(jìn)行底層 DOM 訪問的邏輯,而這一點(diǎn)恰好是指令提供的能力之一。

需要補(bǔ)充Vue 指令相關(guān)知識(shí)的同學(xué)點(diǎn)這里自定義指令

期望使用方式:

<template>
  <input v-model="val" v-debounceInput:600="onInput" />
</template>

<script setup lang="ts">
import { ref } from 'vue'

const val = ref('')
function onInput(e: Event): void {
  console.log(e)
}
</script>

即指令的綁定值為 執(zhí)行邏輯,指令參數(shù)為 防抖時(shí)長(zhǎng)。

指令實(shí)現(xiàn):

import { debounce, isFunction } from '../../utils/index'

let inputFunction: (event: Event) => {}

// 由于要同時(shí)支持 input 輸入框和封裝 input 的組件,因此需要去找到input這個(gè)元素。
function findInput(el: HTMLElement): HTMLElement | null {
  const quene: HTMLElement[] = []
  quene.push(el)
  while (quene.length > 0) {
    const current = quene.shift()
    if (current?.tagName === 'INPUT') {
      return current
    }
    if (current?.childNodes) {
      quene.push(...current.childNodes)
    }
  }
  return null
}

export default {
  mounted(el: HTMLElement, binding: any) {
    const { value, arg } = binding
    if (value && isFunction(value)) {
      let timeout = 600
      if (arg && !Number.isNaN(arg)) {
        timeout = Number(arg)
      }
      inputFunction = debounce(value, timeout) // 執(zhí)行函數(shù)防抖處理
      const input = findInput(el)
      el._INPUT = input
      if (input) {
        input.addEventListener('input', inputFunction)
      }
    }
  },
  beforeUnmount(el: HTMLElement) {
    if (el._INPUT) {
      el._INPUT.removeEventListener('input', inputFunction)
      el._INPUT = null
    }
  }
}

接著處理中文輸入可能會(huì)觸發(fā)多次的問題??山柚?a rel="external nofollow" target="_blank">compositionstart和compositionend來實(shí)現(xiàn)。

  • 輸入法編輯器開始新的輸入合成時(shí)會(huì)觸發(fā) compositionstart 事件。例如,當(dāng)用戶使用拼音輸入法開始輸入漢字時(shí),這個(gè)事件就會(huì)被觸發(fā)。
  • 當(dāng)文本段落的組成完成或取消時(shí),compositionend 事件將被觸發(fā) (具有特殊字符的觸發(fā),需要一系列鍵和其他輸入,如語音識(shí)別或移動(dòng)中的字詞建議)。

在一開始拼音輸入法時(shí)就設(shè)置composing為true,因此在compositionEnd沒有調(diào)用之前都不會(huì)執(zhí)行函數(shù),等compositionEnd調(diào)用,通過dispatchEvent派發(fā)一個(gè)input事件出去,保證邏輯一定會(huì)執(zhí)行。

function compositionStart(event: CompositionEvent) {
  event.target.composing = true
}
function compositionEnd(e: CompositionEvent) {
  e.target.composing = false
  const event = new Event('input', { bubbles: true })
  e.target?.dispatchEvent(event)
}

export default {
  mounted(el: HTMLElement, binding: any) {
    //...
      if (input) {
        input.addEventListener('input', inputFunction)
        input.addEventListener('compositionstart', compositionStart)
        input.addEventListener('compositionend', compositionEnd)
      }
    //...
  },
  beforeUnmount(el: HTMLElement) {
    if (el._INPUT) {
      el._INPUT.removeEventListener('input', inputFunction)
      el._INPUT.removeEventListener('compositionstart', compositionStart)
      el._INPUT.removeEventListener('compositionend', compositionEnd)
    }
  }
}

防抖實(shí)現(xiàn) & 判斷是 function

export function debounce(input: (event: Event) => any, timeout: number): (this: HTMLElement, ev: Event) => any {
  let timer: string | number | NodeJS.Timeout | undefined
  return (event: Event) => {
    // @ts-ignore
    if (event.target.composing === true) {
      return
    }
    if (timer) {
      clearTimeout(timer)
      timer = undefined
    }
    timer = setTimeout(() => {
      input(event)
      clearTimeout(timer)
      timer = undefined
    }, timeout)
  }
}

export function isFunction(param: any): boolean {
  return Object.prototype.toString.call(param) === '[object Function]'
}

注冊(cè)指令(全局注冊(cè)):

createApp(App).directive('debounceInput', debounceInput).mount('#app')

寫個(gè)案例測(cè)試一下:

<template>
  <div>防抖</div>
  <input v-model="val" v-debounceInput="onInput" />
  <div>普通</div>
  <input v-model="count" type="text" @input="onInput" />
</template>

<script setup lang="ts">
import { ref } from 'vue'

const val = ref('')
const count = ref('')
function onInput(e: Event): void {
  console.log('調(diào)用了onInput')
}
</script>

看下最終的效果:

差別還是非常明顯的。指令已發(fā)布npm倉(cāng)庫(kù),有需要可自取。

總結(jié)

??感謝瀏覽,通過本文你可以了解到以下內(nèi)容:

  • 防抖
  • 節(jié)流
  • Vue3指令開發(fā)
  • compositionstart 事件 (需要注意瀏覽器兼容性)
  • compositionend 事件(需要注意瀏覽器兼容性)

到此這篇關(guān)于Vue3指令之搜索框輸入防抖功能實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Vue3搜索框輸入防抖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue使用Element-UI實(shí)現(xiàn)分頁效果全過程

    Vue使用Element-UI實(shí)現(xiàn)分頁效果全過程

    element-ui官網(wǎng)上有分頁實(shí)現(xiàn)的功能,簡(jiǎn)單方便又好用,也有很多分頁的樣式,你可以根據(jù)需要去選擇自己想要的樣式,下面這篇文章主要給大家介紹了關(guān)于Vue使用Element-UI實(shí)現(xiàn)分頁效果的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • 詳解Vuex下Store的模塊化拆分實(shí)踐

    詳解Vuex下Store的模塊化拆分實(shí)踐

    這篇文章主要介紹了詳解Vuex下Store的模塊化拆分實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • vue+element創(chuàng)建動(dòng)態(tài)的form表單及動(dòng)態(tài)生成表格的行和列

    vue+element創(chuàng)建動(dòng)態(tài)的form表單及動(dòng)態(tài)生成表格的行和列

    這篇文章主要介紹了vue+element創(chuàng)建動(dòng)態(tài)的form表單及動(dòng)態(tài)生成表格的行和列 ,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-05-05
  • 記一次Vue中$route序列號(hào)報(bào)錯(cuò)

    記一次Vue中$route序列號(hào)報(bào)錯(cuò)

    本文主要介紹了記一次Vue中$route序列號(hào)報(bào)錯(cuò),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • vue+iview+less+echarts實(shí)戰(zhàn)項(xiàng)目總結(jié)

    vue+iview+less+echarts實(shí)戰(zhàn)項(xiàng)目總結(jié)

    本篇文章是作者通過學(xué)習(xí)vue+iview+less+echarts制作一個(gè)小系統(tǒng)后,做的心得以及遇到的坑的總結(jié),值得大家學(xué)習(xí)參考。
    2018-02-02
  • Vuex modules模式下mapState/mapMutations的操作實(shí)例

    Vuex modules模式下mapState/mapMutations的操作實(shí)例

    這篇文章主要介紹了Vuex modules 模式下 mapState/mapMutations 的操作實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • vue中使用ts配置的具體步驟

    vue中使用ts配置的具體步驟

    這篇文章主要介紹了vue中使用ts配置的具體步驟,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Vue2?與?Vue3?的數(shù)據(jù)綁定原理及實(shí)現(xiàn)

    Vue2?與?Vue3?的數(shù)據(jù)綁定原理及實(shí)現(xiàn)

    這篇文章主要介紹了Vue2與Vue3的數(shù)據(jù)綁定原理及實(shí)現(xiàn),數(shù)據(jù)綁定是一種把用戶界面元素的屬性綁定到特定對(duì)象上面并使其同步的機(jī)制,使開發(fā)人員免于編寫同步視圖模型和視圖的邏輯
    2022-09-09
  • Vue實(shí)現(xiàn)動(dòng)態(tài)圓環(huán)百分比進(jìn)度條

    Vue實(shí)現(xiàn)動(dòng)態(tài)圓環(huán)百分比進(jìn)度條

    這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)動(dòng)態(tài)圓環(huán)百分比進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • vue cli中env的使用指南

    vue cli中env的使用指南

    眾所周知,一個(gè)項(xiàng)目在開發(fā)、測(cè)試與生產(chǎn)環(huán)境的各種配置變量是不一樣的,但在vue cli 3中通過指令vue create xxx創(chuàng)建的項(xiàng)目取消了默認(rèn)的 config 和 build 文件夾,這導(dǎo)致剛?cè)胧值男』锇椴恢涝谀膬号渲铆h(huán)境變量,不過官方也提供了相應(yīng)的配置方法,本文就來介紹一下
    2021-08-08

最新評(píng)論

台北市| 凤山市| 南京市| 姜堰市| 德钦县| 松滋市| 玉门市| 韶山市| 图木舒克市| 东乌珠穆沁旗| 道孚县| 巨鹿县| 京山县| 台南县| 鸡泽县| 邳州市| 库尔勒市| 萝北县| 赣州市| 锡林浩特市| 谢通门县| 三江| 四平市| 兖州市| 海阳市| 马龙县| 高要市| 太仓市| 咸丰县| 法库县| 浦城县| 勃利县| 灵寿县| 会昌县| 平乐县| 闵行区| 青阳县| 桃园市| 荣成市| 贡嘎县| 康平县|