zoukankan      html  css  js  c++  java
  • JavaScript 防抖

    JavaScript 防抖

    在前端开发中会遇到一些频繁的事件触发,比如:

    window resizescroll

    mousedownmousemove

    keyupkeydown...

     

    防抖的原理就是:你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行,总的来说,就是要等你触发完事件 n 秒内不再触发事件,我才执行

    <!DOCTYPE html>
    
    <html >
    
    <head>
    
        <meta charset="utf-8">
    
        <title>防抖</title>
    
        <style>
    
            #container{width:100%;
    
    height:200px;
    
    line-height:200px;
    
    text-align:center;
    
    color: #fff;
    
    background-color: #444;
    
    font-size: 30px;}
    
        </style>
    
    </head>
    
    <body>
    
        <div id="container"></div>
    
        <script>
    
            var count = 1;
    
            var container = document.getElementById('container');
    
            function getUserAction() {
    
                container.innerHTML = count++;
    
            };
    
            container.onmousemove = getUserAction;
    
        </script>
    
    </body>
    
    </html>

    1每次次事件触发,都会清除上次事件的定时器,达到连续触发,只执行一次的效果

    function debounce(func, wait) {
    
        var timeout;
    
        return function () {
    
            clearTimeout(timeout)

            //每次次事件触发,都会清除上次事件的定时器,达到连续触发,只执行一次的效果

    
    

            timeout = setTimeout(func, wait);

    
    

        }

    
    

    }

    
    

    container.onmousemove = debounce(getUserAction, 1000);

     

    现在随你怎么移动,反正你移动完 1000ms 内不再触发,我才执行事件。看看使用效果:

     

    2.this

    如果我们在 getUserAction 函数中 console.log(this),在不使用 debounce 函数的时候,this 指向的的值为:

    <div id="container"></div>

    但是如果使用我们的 debounce 函数,this 就会指向 Window 对象!

    所以我们需要将 this 指向正确的对象

    function debounce(func, wait) {
    
        var timeout;
    
        return function () {
    
            var context = this;//保存事件this
    
            clearTimeout(timeout)
    
            timeout = setTimeout(function () {
    
                func.apply(context)//重新绑定this
    
            }, wait);
    
        }
    
    }
    

    3.event 对象

    JavaScript 在事件处理函数中会提供事件对象 event,我们修改下 getUserAction 函数:

    function getUserAction(e) {

        console.log(e);

        container.innerHTML = count++;

    };

    如果我们不使用 debouce 函数,这里会打印 MouseEvent 对象

    但是在我们实现的 debounce 函数中,却只会打印 undefined!重新绑定事件对象

    function debounce(func, wait) {
    
        var timeout;
    
        return function () {
    
            var context = this;
    
            var args = arguments;//获取return 函数的参数
    
            clearTimeout(timeout)
    
            timeout = setTimeout(function () {
    
                func.apply(context, args)//重新调用函数时指定参数
    
            }, wait);
    
        }
    
    }

    4.立刻执行

    这个时候,接下来思考一个新的需求。

    我不希望非要等到事件停止触发后才执行,我希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行。,那我们加个 immediate 参数判断是否是立刻执行。

    事件发生后,函数立即执行

    function debounce(func, wait, immediate) {
    
        var timeout;
    
        return function () {
    
            var context = this;
    
            var args = arguments;
    
            if (timeout) clearTimeout(timeout);//
    
            if (immediate) {//立即执行逻辑
    
                //--------------构成是是否判断----------------
    
                var callNow = !timeout;
    
                timeout = setTimeout(function () {
    
                    timeout = null;//连续事件触发,下次能执行时间会一致往后移wait,除非等待时间结束后再触发
    
                }, wait)
    
                //--------------构成是是否判断end----------------
    
                if (callNow) func.apply(context, args)//是第一次触发
    
            }
    
            else {//非立即执行
    
                timeout = setTimeout(function () {
    
                    func.apply(context, args)
    
                }, wait);
    
            }
    
        }
    
    }

    5.返回值

    此时注意一点,就是 getUserAction 函数可能是有返回值的,所以我们也要返回函数的执行结果,但是当 immediate false 的时候,因为使用了 setTimeout ,我们将 func.apply(context, args) 的返回值赋给变量,最后再 return 的时候,值将会一直是 undefined,所以我们只在 immediate true 的时候返回函数的执行结果。

    function debounce(func, wait, immediate) {
    
        var timeout, result;
    
        return function () {
    
            var context = this;
    
            var args = arguments;
    
            if (timeout) clearTimeout(timeout);
    
            if (immediate) {
    
                var callNow = !timeout;
    
                timeout = setTimeout(function(){
    
                    timeout = null;
    
                }, wait)
    
                if (callNow) result = func.apply(context, args)//只能立即执行才能有返回值
    
            }
    
            else {
    
                timeout = setTimeout(function(){
    
                    func.apply(context, args)
    
                }, wait);
    
            }
    
            return result;//在这里返回,非立即执行会报undefined
    
        }
    
    }
    
     
  • 相关阅读:
    Mysql 8.0 OCP认证考试原题题库整理(CUUG内部资料)-第2题
    Mysql 8.0 OCP认证考试原题题库整理(CUUG内部资料)-第1题
    【2020年8月】Oracle OCP 062考试新题(-3题)CUUG内部题库
    【2020年8月】Oracle OCP 062考试新题(-2题)CUUG内部题库
    iOS7时代我们用什么来追踪和识别用户?
    插件就是生产力——那些不能错过的XCode插件们
    批处理执行Testng
    Jmeter调度器小记
    Newtonsoft.Json小记
    批处理添加环境变量
  • 原文地址:https://www.cnblogs.com/li923/p/11428940.html
Copyright © 2011-2022 走看看