What are anti-shake and throttling?
Stabilization and throttling are essentially front ends 对过高频率执行的限制
.
防抖
: Execute the callback after n seconds after the event is triggered, if it is triggered again within these n seconds, restart the timing.
节流
: It is stipulated that the function can only be triggered once in a unit time. If the function is triggered multiple times within this unit time, only one time will take effect.
Anti-shake is a bus, wait for 30 seconds after the last person comes up, and restart the timer every time someone comes up.
The throttling is the subway, and there is only one train within five minutes.
1. Anti-shake
Don't use anti-shake blindly, there are 3 conditions for using anti-shake:
- frequently calling a function
- cause efficiency problems
- The required result is subject to the last time
Application scenario:
- Frequently enter content in the input box, search or submit information
- Click the button frequently to trigger an event
- Listen to browser scrolling events to complete some specific operations
- The resize event when the user zooms the browser
1. Encapsulate an anti-shake function
Solve the general first, then solve the this point, and then solve the parameter problem
function debounce(func, delay = 500) {
let timerId;
return function (...args) {
// 因为this指向问题 这里写普通函数
clearTimeout(timerId)
timerId = setTimeout(() => {
func.apply(this, args) // 箭头函数没有this
clearTimeout(timerId) // 这两行不加也行
timerId= null
}, delay)
}
}
const debouncedFunction = debounce(myFunction, 500)
window.onresize = debouncedFunction()
2. Vue2 custom anti-shake command
partial registration
<template>
<input v-model="searchQuery" v-debounce="handleSearch" :debounce-delay="500" />
</template>
<script>
export default {
data() {
return {
searchQuery: ''
};
},
methods: {
handleSearch() {
console.log('Search query:', this.searchQuery)
},
},
directives: {
debounce: {
inserted: function (el, binding) {
let timer
el.addEventListener('input', function () {
clearTimeout(timer)
timer = setTimeout(function () {
binding.value()
}, binding.arg || 500)
})
}
}
}
}
</script>
global registration
// directives/debounce.js
import Vue from 'vue'
Vue.directive('debounce', {
inserted: function (el, binding) {
let timer
el.addEventListener('input', function () {
clearTimeout(timer)
timer = setTimeout(function () {
binding.value()
}, binding.value || 500)
})
}
})
// main.js (或你的入口文件)
import Vue from 'vue'
import App from './App.vue'
import './directives/debounce'; // 导入自定义指令
new Vue({
render: (h) => h(App)
}).$mount('#app')
3. Vue3 custom anti-shake command
partial registration
<template>
<input v-model="searchQuery" v-debounce="handleSearch" :debounce-delay="500" />
</template>
<script>
import {
ref, defineComponent } from 'vue'
import debounceDirective from './directives/debounce' // 导入自定义指令
export default defineComponent({
directives: {
debounce: debounceDirective, // 局部注册自定义指令
},
setup() {
const searchQuery = ref('')
function handleSearch() {
// 这里放置搜索逻辑
console.log('搜索关键词:', searchQuery.value)
}
return {
searchQuery,
handleSearch,
}
}
})
</script>
// directives/debounce.js
export default {
mounted(el, binding) {
let timer
el.addEventListener('input', function () {
clearTimeout(timer)
timer = setTimeout(function () {
binding.value()
}, binding.value || 500)
})
}
}
global registration
<template>
<input v-model="searchQuery" v-debounce="handleSearch" :debounce-delay="500" />
</template>
<script>
import {
ref } from 'vue'
export default {
setup() {
const searchQuery = ref('')
function handleSearch() {
// 这里放置搜索逻辑
console.log('搜索关键词:', searchQuery.value)
}
return {
searchQuery,
handleSearch,
}
}
}
</script>
// directives/debounce.js
export default {
mounted(el, binding) {
let timer
el.addEventListener('input', function () {
clearTimeout(timer)
timer = setTimeout(function () {
binding.value()
}, binding.value || 500)
})
}
}
// main.js (或你的入口文件)
import {
createApp } from 'vue'
import App from './App.vue'
import debounceDirective from './directives/debounce' // 导入自定义指令
const app = createApp(App)
// 全局注册自定义指令
app.directive('debounce', debounceDirective)
app.mount('#app')
//debounce.ts
import {
App, DirectiveBinding } from 'vue'
export default (app: App<Element>) => {
app.directive('debounce', {
mounted(el: HTMLElement, binding: DirectiveBinding) {
let timer: NodeJS.Timeout | null = null
el.addEventListener('click', () => {
const firstClick = !timer
if (firstClick) {
binding.value()
}
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
timer = null
if (!firstClick) {
binding.value()
}
}, 1000)
})
}
})
}
// main.ts
import debounce from '@/directives/debounce'
app.use(debounce)
v-debounce="search"
example:
<template>
<div>
<input v-model="inputValue" @keydown.enter="handleInputEnter" />
</div>
</template>
import {
ref } from 'vue';
export default {
setup() {
const inputValue = ref('')
// 封装防抖函数
const debounce = (fn, delay) => {
let timer;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments)
}, delay)
}
}
// 处理输入事件的防抖函数
const handleInputEnterDebounced = debounce(() => {
// 在这里处理输入内容的逻辑
console.log('Enter key pressed!')
console.log('Input value:', inputValue.value);
}, 500) // 设置防抖延迟时间为500毫秒
// 输入事件处理函数
const handleInputEnter = () => {
handleInputEnterDebounced() // 使用防抖函数处理输入事件
};
return {
inputValue,
handleInputEnter
}
}
}
Two, throttling
Application scenario:
- Listen to page scroll events
- mouse move event
- The user frequently clicks the button to operate
- some designs in the game
1. Encapsulate a throttling function
var throttle = function(func, delay = 500) {
let timer = null
return function(...args) {
if (!timer) {
timer = setTimeout(function() {
func.apply(this, args)
clearTimeout(timer)
timer = null
}, delay)
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000))
2. vue2 custom throttling command
partial registration
<template>
<input v-model="searchQuery" v-throttle="handleSearch" :throttle-delay="500" />
</template>
<script>
export default {
data() {
return {
searchQuery: ''
};
},
directives: {
throttle: {
inserted: function (el, binding) {
let timer = null
el.addEventListener('input', function () {
if (!timer) {
timer = setTimeout(function () {
binding.value()
timer = null
}, binding.arg || 500)
}
})
}
}
},
methods: {
handleSearch() {
// 这里放置搜索逻辑
console.log('搜索关键词:', this.searchQuery)
}
}
}
</script>
global registration
import Vue from 'vue'
import App from './App.vue'
// 自定义节流指令
Vue.directive('throttle', {
inserted: function (el, binding) {
let timer = null
el.addEventListener('input', function () {
if (!timer) {
timer = setTimeout(function () {
binding.value()
timer = null
}, binding.arg || 500)
}
})
}
})
new Vue({
render: (h) => h(App)
}).$mount('#app')
// directive/throttle.js
export default {
inserted: function (el, binding) {
let timer = null
el.addEventListener('input', function () {
if (!timer) {
timer = setTimeout(function () {
binding.value()
timer = null
}, binding.arg || 500)
}
})
}
}
// main.js (或你的入口文件)
import Vue from 'vue'
import App from './App.vue'
import throttleDirective from './directive/throttle'
// 自定义节流指令全局注册
Vue.directive('throttle', throttleDirective)
new Vue({
render: (h) => h(App)
}).$mount('#app')
3. vue3 custom throttling command
// main.js (或你的入口文件)
import {
createApp } from 'vue';
import App from './App.vue';
import throttleDirective from './directives/throttle';
const app = createApp(App);
// 自定义节流指令全局注册
app.directive('throttle', throttleDirective);
app.mount('#app')
// directives/throttle.js
export default {
beforeMount(el, binding) {
let timer = null
el.addEventListener('input', () => {
if (!timer) {
timer = setTimeout(() => {
binding.value()
timer = null
}, binding.arg || 500)
}
})
}
}
// throttle.ts
import {
App, DirectiveBinding } from 'vue'
export default (app: App<Element>) => {
app.directive('throttle', {
mounted(el: HTMLElement, binding: DirectiveBinding) {
let timer: NodeJS.Timeout | null = null
el.addEventListener('click', () => {
if (!timer) {
timer = setTimeout(() => {
binding.value()
timer = null
}, 5000)
}
})
}
})
}
example:
<template>
<!-- <RouterView /> -->
<div class="aaa" @mousemove="move"></div>
</template>
<script setup lang="ts">
// import { RouterView } from 'vue-router'
const throttle = (fn, delay = 500) => {
let timeId = null
return function(...args) {
if (!timeId) {
timeId = setTimeout(function() {
fn.apply(this, args)
clearTimeout(timeId)
timeId = null
}, delay)
}
}
}
const move = throttle((e) => {
console.log('Mouse coordinates:', e.clientX, e.clientY)
}, 1000)
</script>
<style lang="less">
.aaa{
width: 800px;
height: 800px;
background-color: pink;
z-index: 999;
}
</style>