Let's talk about anti-shake and throttling

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>

Guess you like

Origin blog.csdn.net/weixin_44582045/article/details/131829040