Stay Hungry,Stay Foolish!

JavaScript实现绑定DOM的定时器插件

问题

使用原生的setTimeout和setInterval仅仅能够实现, 定时执行事件处理函数,

在网页开发中, 往往会出现一种情况,定时器用于定时更新某个页面区域的数据,

往往在页面加载之后, 就启动这个定时器, 往后则间隔执行此定时器。

 

页面上定时刷新的区域可能会动态消失, 特别是在ajax被广泛使用的今天,

如果定时刷新的区域被删除了, 则定时器材也需要自动清除掉。

 

此二个接口,如果实现这种效果需要, 自己维护定时器句柄, 并且在处理定时器事件函数的时候,

首先判断 指定的刷新区域是否还是存在的?  如果还存在, 则继续执行数据刷新的逻辑,

如果不存在, 则删除定时器,不执行数据刷新的动作。

 

方案

此类定时器需要与 目标DOM进行绑定, 在事件处理函数中, 判断如果DOM被删除, 则清理定时器。

 

Code

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>My First WebComponent</title>
</head>
<body>
    <input type="text" id="test" name="test" value="test"></input>
    <input type="button" id="removetest" name="removetest" value="removetest"></input>
    <script type="text/javascript">
    /************************ timer定时器插件 start **********************/
    (function () {
        /* 此函数让 定时器处理handler,
            可以获取到 调用 setTimeout_context_binding 的对象 */
        var setTimeout_context_binding = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
          var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
          return window.setTimeout(vCallback instanceof Function ? function () {
                vCallback.apply(oThis, aArgs);
          } : vCallback, nDelay);
        };

        /* 此函数让 定时器处理handler,
            可以获取到 调用 setTimeout_context_binding 的对象 */
        var setInterval_context_binding = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) {
            var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
            return window.setInterval(vCallback instanceof Function ? function() {
                vCallback.apply(oThis, aArgs);
            } : vCallback, nDelay);
        };

        /* 定义定时器的构造函数 */
        var timer = function(fnAlarm, options)
        {
            /* external settable */
            this.fnAlarm_inner = function(){
                $("#timer_msg").printMsg(this.timerHandle.toString()
                    + "-please add custom fnAlarm")
            };

            this.timeout = undefined;
            this.interval = undefined;
            this.contextDom = undefined;

            /* inner maintain variable */
            this.timerHandle;

            /* set external variable */
            if ( fnAlarm )
            {
                this.fnAlarm_inner = fnAlarm;
            }

            if ( options )
            {
                if ( options.timeout )
                {
                    this.timeout = options.timeout;
                }

                if ( options.interval )
                {
                    this.interval = options.interval;
                }

                if ( options.contextDom )
                {
                    this.contextDom = options.contextDom;
                }
            }
        }

        /* 定义定时器的原型方法 */
        timer.prototype.start = function(){
            var context_binding_timer = undefined;
            var time_value = undefined;

            if ( this.timeout ) {
                context_binding_timer = setTimeout_context_binding;
                time_value = this.timeout;
            } else {
                context_binding_timer = setInterval_context_binding;
                time_value = this.interval;
            }

            this.timerHandle = context_binding_timer.call(this, function(){
                /* 上下文DOM绑定的目的在这里:
                    如果此定时器绑定的DOM已经从文档中删除,则不调用定时处理handler */
                if ( this.contextDom && !document.body.contains(this.contextDom) )
                {
                    this.stop();
                    return;
                }

                this.fnAlarm_inner.call(this);
                delete this.timerHandle;
            }, time_value);
        };

        timer.prototype.stop = function(){
            if ( this.timeout ) {
                clearTimeout(this.timerHandle)
            } else {
                clearInterval(this.timerHandle)
            }
            delete this.timerHandle;
        };

        timer.prototype.getTimerID = function(){
            return this.timerHandle;
        };

        /* 开放接口 */
        window.ContextBindingTimer = timer;
    })();
    /************************ timer定时器插件 end **********************/

    //bind remove button event
    document.getElementById("removetest").onclick=function(){
        var test = document.getElementById("test");
        test.parentNode.removeChild(test);
    }

    var targetDom = document.getElementById("test");

    /* construct a interval timer with setTimeout timer */
    var timer = new ContextBindingTimer(function(){
        console.log("access once!")
    }, {timeout:1000, contextDom:targetDom})
       
    timer.start()
    </script>
</body>
</html>

 

Implementation effect

页面上输入框删除之前, 定时器打印数目一直增加。

image

点击按钮删除输入框之后, 定时器打印数据则没有变化了, 证明定时器已经被删除。

image

posted @ 2016-05-06 22:28  lightsong  阅读(1387)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel