溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

vue使用節(jié)流函數(shù)會遇到什么問題

發(fā)布時間:2021-05-20 11:59:13 來源:億速云 閱讀:171 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下vue使用節(jié)流函數(shù)會遇到什么問題,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

舉一個? 業(yè)務(wù)場景

vue使用節(jié)流函數(shù)會遇到什么問題

概念:

關(guān)于防抖函數(shù)的介紹

關(guān)于addEventListener

使用示例:

function debounce(fn) {
        let timeout = null; // 創(chuàng)建一個標記用來存放定時器的返回值
        return function () {
            clearTimeout(timeout); // 每當用戶輸入的時候把前一個 setTimeout clear 掉
            timeout = setTimeout(() => {
                // 然后又創(chuàng)建一個新的 setTimeout, 這樣就能保證輸入字符后的
                // interval 間隔內(nèi)如果還有字符輸入的話,就不會執(zhí)行 fn 函數(shù)
                fn.apply(this, arguments);
            }, 500);
        };
    }
    function sayHi() {
        console.log('防抖成功');
    }

    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // 防抖

在vue中使用?

首先說一下之前的踩坑行為

下面的代碼為簡易版的一個場景

function debounce(fn) {
        let timeout = null; // 創(chuàng)建一個標記用來存放定時器的返回值
        return function () {
            clearTimeout(timeout); // 每當用戶輸入的時候把前一個 setTimeout clear 掉
            timeout = setTimeout(() => {
                // 然后又創(chuàng)建一個新的 setTimeout, 這樣就能保證輸入字符后的
                // interval 間隔內(nèi)如果還有字符輸入的話,就不會執(zhí)行 fn 函數(shù)
                fn.apply(this, arguments);
            }, 500);
        };
   }

錯誤的使用方式

<template>
    <div class="search-view">
        <div class="header">
            <Search 
                class="search-box" 
                v-model='searchValue' 
                @input='getSearchResult' 
                placeholder='搜索想要的好物' />
            <span @click="goBack" class="cancel">取消</span>
        </div>
        <div class="serach-view-content" />
    </div>

</template>

<script>
import Search from './components/Search';
import debounce from './config';

export default {
    name: 'SearchView',
    components: {
        Search
    },
    data() {
        return {
            searchValue: ''
        };
    },
    methods: {
        getSearchResult() {
            debounce(function() {
                console.log(this.searchValue);
            })();
        }
    }
};
</script>

為什么錯誤?

源碼層級分析

vue模板編譯 的解析事件

export const onRE = /^@|^v-on:/
export const dirRE = /^v-|^@|^:/

function processAttrs (el) {
  const list = el.attrsList
  let i, l, name, value, modifiers
  for (i = 0, l = list.length; i < l; i++) {
    name  = list[i].name
    value = list[i].value
    if (dirRE.test(name)) {
      // 解析修飾符
      modifiers = parseModifiers(name)
      if (modifiers) {
        name = name.replace(modifierRE, '')
      }
      if (onRE.test(name)) { // v-on
        name = name.replace(onRE, '')
        addHandler(el, name, value, modifiers, false, warn)
      }
    }
  }
}

總結(jié): 實例初始化階段調(diào)用的初始化事件函數(shù)initEvents實際上初始化的是父組件在模板中使用v-on或@注冊的監(jiān)聽子組件內(nèi)觸發(fā)的事件

vue的事件機制

Vue.prototype.$on = function(event, fn) {
    const vm = this;
    if (Array.isArray(event)) {
        for (let i = 0; i < event.length; i++) {
            this.$on(event[i], fn);
        }
    } else {
        //這個_events屬性就是用來作為當前實例的事件中心,所有綁定在這個實例上的事件都會存儲在事件中心_events屬性中。
        (vm._events[event] || (vm._events[event] = [])).push(fn);
    }
    return vm;
};

Vue.prototype.$emit = function(event) {
    const vm = this;
    let cbs = vm._events[event];
    if (cbs) {
        cbs = cbs.length > 1 ? toArray(cbs) : cbs;
        let args = toArray(arguments, 1);
        for (let i = 0; i < cbs.length; i++) {
            try {
                cbs[i].apply(vm, args);
            } catch (e) {
                handleError(e, vm, `event handler for "${event}"`);
            }
        }
    }
    return vm;
};

vue的initState中 調(diào)用了initMethods方法

initMethods中掛在methods方法到this上

for (const key in methods) {
        if (process.env.NODE_ENV !== 'production') {
            if (methods[key] == null) {
                warn(
                    `Method "${key}" has an undefined value in the component definition. ` +
                        `Did you reference the function correctly?`,
                    vm
                );
            }
            // 如果和props中某個屬性名重名了 拋出異常
            if (props && hasOwn(props, key)) {
                warn(`Method "${key}" has already been defined as a prop.`, vm);
            }
            /*
            如果methods中某個方法名如果在實例vm中已經(jīng)存在并且方法名是以_或$開頭的,就拋出異常:
            提示用戶方法名命名不規(guī)范
            */
            if (key in vm && isReserved(key)) {
                warn(
                    `Method "${key}" conflicts with an existing Vue instance method. ` +
                        `Avoid defining component methods that start with _ or $.`
                );
            }
            // 將method綁定到實例 vm上  這樣我們就可以通過this.xxx 來訪問了
            // 同時如果在vue中  let m1 = this.xxx  m1() this也指向vue
            vm[key] = methods[key] == null ? noop : bind(methods[key], vm);
        }

劃重點:

  • 子組件$emit('input事件')

  • 父組件接收事件

getSearchResult.apply(this, agrs)
<===>  apply的調(diào)用可以寫成下面的形式
this.getSearchResult(args)

// 進而變成這種執(zhí)行
debounce(function() {
      console.log(this.searchValue);
})();

// 這里的debounce 返回了一個函數(shù) 于是變成
(function (fn) {
      clearTimeout(timeout); // 每當用戶輸入的時候把前一個 setTimeout clear 掉
      timeout = setTimeout(() => {
          // 然后又創(chuàng)建一個新的 setTimeout, 這樣就能保證輸入字符后的
          // interval 間隔內(nèi)如果還有字符輸入的話,就不會執(zhí)行 fn 函數(shù)
          fn.apply(this, arguments);
      }, 500);
})()
// 到這里  其實就變成了匿名函數(shù)的自執(zhí)行
// 由于每次觸發(fā)input都會返回一個新的匿名函數(shù)  生成一個新的函數(shù)執(zhí)行棧  所以防抖失效~

那么應(yīng)該如何調(diào)用

<template>
    <div class="search-view">
        <div class="header">
            <Search
                class="search-box"
                v-model='searchValue'
                @input='getSearchResult()'
                placeholder='搜索想要的好物'
            />
            <span
                @click="goBack"
                class="cancel">取消</span>
        </div>
        <div class="serach-view-content">
            
        </div>
    </div>

</template>

<script>
import debounce from 'lodash.debounce';
export default {
    name: 'SearchView',
    components: {
        Search,
    },
    data() {
        return {
            searchValue: '',
        };
    },
    methods: {
        getSearchResult: debounce(function () {
            console.log(this.searchValue);
        }, 500),
    },

};
</script>

分析執(zhí)行過程

getSearchResult().apply(this, args)
<===> 忽略參數(shù)行為 只關(guān)注執(zhí)行棧

let func = function () {
    clearTimeout(timeout); // 每當用戶輸入的時候把前一個 setTimeout clear 掉
    timeout = setTimeout(() => {
        // 然后又創(chuàng)建一個新的 setTimeout, 這樣就能保證輸入字符后的
        // interval 間隔內(nèi)如果還有字符輸入的話,就不會執(zhí)行 fn 函數(shù)
        fn.apply(this, arguments);
    }, 500);
};

this.func(args)

<===>

子組件觸發(fā)input的行為  返回的始終是一個同一個函數(shù)體  防抖成功

Vue的優(yōu)點

Vue具體輕量級框架、簡單易學(xué)、雙向數(shù)據(jù)綁定、組件化、數(shù)據(jù)和結(jié)構(gòu)的分離、虛擬DOM、運行速度快等優(yōu)勢,Vue中頁面使用的是局部刷新,不用每次跳轉(zhuǎn)頁面都要請求所有數(shù)據(jù)和dom,可以大大提升訪問速度和用戶體驗。

以上是“vue使用節(jié)流函數(shù)會遇到什么問題”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI