vue元件中節流函式的失效的原因和解決方法
今天使用節流函式的時候遇見了一個問題,搞了半天才找到原因,所以在這裡做個總結。
節流函式
瀏覽器的一些事件,如:resize,scroll,mousemove等。這些事件觸發頻率太過頻繁,繫結在這些事件上的回撥函式會不停的被呼叫,加重瀏覽器的負擔,導致使用者體驗非常糟糕。所以先賢們發明了節流函式,簡單版本如下:
function throttle (f,wait = 200) { let last = 0 return function (...args) { let now = Date.now() if (now - last > wait) { last = now f.apply(this,args) } } }
假設有一個 vue 元件 svgMark。這個元件中渲染的元素要在頁面視窗大小發生變化時重繪 reDraw ,而重繪時要使用節流函式防止效能損耗。正常情況下程式碼如下:
<template> <div>{{ index }}</div> </template> <script> import { throttle } from 'lodash' export default { name: 'SvgMark',data() { return { index: 0 } },mounted() { window.addEventListener('resize',this.reDraw) },beforeDestroy() { window.removeEventListener('resize',methods: { reDraw: throttle(function() { this.index++ },500) } } </script> </script>
一般情況下這樣用沒什麼問題。但是有這樣一個場景,使用節流函式時卻失效了,即當這個元件被 v-for 迴圈載入了很多次:
<template> <div> <svgMark v-for="item in 10" :key="item.id" /> </div> </template>
這個時候無論渲染了多少個 svgMark 元件,在視窗大小改變的時候卻只觸發了第一個元件和第 n 割元件的重繪,為什麼其他元件沒有觸發呢?這就要從頭說起了。
- 節流函式
節流函式在初始化的時候產生了一個閉包,閉包內儲存了變數 last ,這個 last 記錄了上一次執行 f 函式的時間。而當下一次觸發節流函式的時候,如果此時時間 now 減去上次時間 last 小於了我們規定的節流時間 wait ,那麼函式 f 將不會執行。
很顯然,第一個子元件在觸發節流函式的時候產生了一個 last,而第二個元件在觸發節流函式時候的時產生的 now 並沒有滿足 now - last > wait 的條件,所以沒有執行重繪程式碼。而到了第 n 個元件觸發節流函式的時候,滿足了 now - last > wait 的條件所以重繪成功了。
- vue 元件
vue 元件在程式碼編譯的階段,元件 svgMark 中的方法 reDraw: throttle(function() { this.index++ },500) 就已經被編譯成了類似如下函式:
reDraw: ƒ (...args) { let now = Date.now() if (now - last > wait) { last = now f.apply(this,args) } }
由於函式是引用型別,所有使用子元件 svgMark 的 methods 中的 reDraw 都指向了同一個記憶體地址,也就是說所有子元件的 reDraw 方法都是同一個函式。
因為所有元件都公用了同一個節流函式,當然就會產生節流了。那怎麼解決問題呢?對症下藥就要讓每個元件產生自己的節流函式,而不產生共用。程式碼如下
子元件:
<template> <div>{{ index }}</div> </template> <script> import { throttle } from 'lodash' export default { name: 'SvgMark',mounted() { this.reDraw = throttle(() => { this.index++ },500) window.addEventListener('resize',this.reDraw) } } </script>
我們在 mounted 宣告周期函式中手動聲明瞭 reDraw 函式替代 methods 中的 reDraw ,這樣在每個元件初始化的時候都會產生一個自己的節流函數了。需要注意此時節流函式的引數使用了箭頭函式,因為這樣 this 才會指向元件例項。
以上就是節流函式帶給我的坑,現在分享給大家。[下班][鼓掌]
以上就是vue元件中節流函式的失效和解決方法的詳細內容,更多關於vue 元件節流函式的資料請關注我們其它相關文章!