初級
1、先寫好防抖函數
/**
* @desc 防抖函數
* @param {需要防抖的函數} func
* @param {延遲時間} wait
* @param {是否立即執行} immediate
*/
export function debounce(func, wait, immediate) {
let timeout
return function(...args) {
let context = this
if (timeout) clearTimeout(timeout)
if (immediate) {
let callNow = !timeout
timeout = setTimeout(function() {
timeout = null
}, wait)
if (callNow) func.apply(context, args)
} else {
timeout = setTimeout(function() {
func.apply(context, args)
}, wait)
}
}
}
2、然後在要使用的組件裏 import
進來
import { debounce } from 'xxx'
export default {
data: {
return {
vm: this
}
},
methods: {
toDoSth: debounce((vm) => {
// 這裏將當前組件實例當參數傳入
// 就可以使用實例中定義的一些屬性、方法
},
500,
true
)
}
}
3、在組件方法中使用
template:
<div @click="toDoSth(vm)"></div>
高級
雖然上面的寫法已經能解決問題了,但是總覺得不夠美觀。
在網上搜索一番,看到有個哥們將防抖封裝成一個組件,果然和我想的一樣。不過這哥們直接將上下文當參數傳進來了,比我把整個實例傳進來高明,我在這個基礎上添加了 immediate 的功能,還有添加了默認不傳 event 參數的情況處理。
debounce.js 文件:
import Vue from 'vue'
const debounce = (func, time, ctx, immediate) => {
let timer
const rtn = (...params) => {
clearTimeout(timer)
if (immediate) {
let callNow = !timer
timer = setTimeout(() => {
timer = null
}, time)
if (callNow) func.apply(ctx, params)
} else {
timer = setTimeout(() => {
func.apply(ctx, params)
}, time)
}
}
return rtn
}
Vue.component('Debounce', {
abstract: true,
props: ['time', 'events', 'immediate'],
created() {
this.eventKeys = this.events && this.events.split(',')
this.originMap = {}
this.debouncedMap = {}
},
render() {
const vnode = this.$slots.default[0]
// 如果默認沒有傳 events,則對所有綁定事件加上防抖
if (!this.eventKeys) {
this.eventKeys = Object.keys(vnode.data.on)
}
this.eventKeys.forEach(key => {
const target = vnode.data.on[key]
if (target === this.originMap[key] && this.debouncedMap[key]) {
vnode.data.on[key] = this.debouncedMap[key]
} else if (target) {
this.originMap[key] = target
this.debouncedMap[key] = debounce(target, this.time, vnode, this.immediate)
vnode.data.on[key] = this.debouncedMap[key]
}
})
return vnode
}
})
使用方式:
1、引入 debounce.js 文件
import 'xxx/debounce.js'
export default {
methods: {
toDoSth(e) {
// 這裏正常寫就可以了
}
}
}
2、在模版裏使用。
其中time爲必選參數。 event 和 immediate 參數都是可選參數。
如果組件下有多個事件綁定,那麼 event 可以自定義需要進行防抖處理的事件。
如果需要立即執行的話,可以將 immediate 參數設置爲 true。
<Debounce :time="500" event="click" :immediate="true">
<button @click="toDoSth($event, 1)">click me</button>
</Debounce>
到此就完成了一次 Debounce 組件的封裝。
參考:
最後附上這位哥們的原帖:
https://juejin.im/post/5c2dc7a9e51d4573c8491e77