设计模式知识连载(40)---节流模式:

<body>


<h3>设计模式知识连载(40)---节流模式:</h3>
<p>
    对重复的业务逻辑进行节流控制,执行最后一次操作并取消其他操作,以提高性能
    【该demo暂时不能执行】
</p>

<hr>
<div style="height: 1000px; border: 1px solid red"></div>
<button id = 'back'>返回首页</button>
<hr>

<div id="icon" class="icon">
    <ul class="icon">
        <li class="weixin"></li>
        <li class="weibo"></li>
    </ul>
    <div class="">
        <img class="show" src='img/weixin.png' alt=''>
        <img src='img/weibo.png' alt=''>
        <span class="arrow"><em></em></span>
    </div>
</div>

<hr>
<div id="container">

</div>

<hr>

<button id = 'btn'>test</button>


<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/jquery-easing/1.4.1/jquery.easing.min.js"></script>
<script type="text/javascript">



    /**
    *   案例一:返回顶部按钮,方式一:初始
    *   【失败,没达到预期效果】
    */
    // 节流器
    var throttle = function() {

        // 获取第一个参数
        var isClear = arguments[0];
        var fn ;

        console.log(typeof isClear === 'boolean' ) ;

        if(typeof isClear === 'boolean') {
            console.log('这是boolean') ;
            // 第二个参数则为函数
            fn = arguments[1] ;

            // 函数的计时器句柄存在,则清除该计时器
            fn.__throttleID && clearTimeout(fn.__throttleID) ;
        }else{
            console.log('这是function') ;
            // 第一个参数为函数
            fn = isClear ;
            // 第二个参数为函数执行时的参数
            param = arguments[1] ;
            // 对执行时的参数适配默认值,用extend方法【用到jquery.min.js】
            var p = $.extend({
                context : null ,    // 执行函数执行时的作用域
                args : [],          // 执行函数执行时的相关参数(IE下要为数组)
                time : 300          // 执行函数延迟执行的时间  
            }, param) ;
            // 清除执行函数计时器句柄
            arguments.callee(true, fn) ;
            // 为函数绑定计时器句柄,延迟执行函数
            fn.__throttleID = setTimeout(function() {
                // 执行函数
                fn.apply(p.context, p.args) ;
            }, p.time) ;
        }
    }

    // 测试用例
    function moveScroll() {
        var top = $(document).scrollTop() ;
        //【用到jquery.easing.min.js】
        $('#back').animate({top : top + 300}, 400, 'easeOutCubic') ;
    }
    // 监听页面滚动条事件
    $(window).on('scroll', function() {
        // 节流执行返回顶部按钮动画
        throttle(moveScroll) ;
    }) ;



    /**
    *   案例二:优化浮层,方式一:初始
    */
    // 外观模式封装获取元素方法
    function $(id) {
        return document.getElementById(id) ;
    }
    function $tag(tag, container) {
        container = container || document ;
        return container.getElementgTagName(tag) ;
    }
    // 浮层类
    var Layer = function(id) {
        // 获取容器
        this.container = $(id) ;
        // 获取容器中的浮层容器
        this.layer = $tag('div', this.container)[0] ;
        // 获取icon容器
        this.lis = $tag('li', this.container) ;
        // 获取二维码图片
        this.imgs = $tag('img', this.container) ;
        // 绑定事件
        this.bindEvent() ;
    }
    Layer.prototype = {
        // 绑定交互事件
        bindEvent : function() {
            // 缓存当前对象
            var that = this ;
            // 隐藏浮层
            function hideLayer() {
                that.layer.className = '' ;
            }
            // 显示浮层
            function showLayer() {
                that.layer.className = 'show' ;
            }
            // 鼠标光标已入事件
            that.on(that.container, 'mouseenter', function() {
                // 清除隐藏浮层方法计时器
                throttle(true, hideLayer) ;
                // 延迟显示浮层方法
                throttle(showLayer) ;
            // 鼠标光标移除事件 
            }).on(that.container, 'mouseleave', function() {
                // 延迟浮层隐藏方法
                throttle(hideLayer) ;
                // 清除显示浮层方法计时器
                throttle(true, showLayer) ;
            }) ;
            // 遍历icon绑定事件
            for(var i = 0; i < that.lis.length; i++) {
                // 自定义属性index
                that.lis[i].index = i ;
                // 为每一个li元素绑定鼠标移入事件
                that.on(that.lis[i], 'mouseenter', function() {
                    // 获取自定义属性index
                    var index = this.index ;
                    // 排除所有img的show类
                    for(var i = 0; i < that.imgs.length; i++) {
                        that.imgs[i].className = '' ;
                    }
                    // 为目标图片设置show类
                    that.imgs[index].className = 'show' ;
                    // 从新定义浮层位置
                    that.layer.style.left = -22 + 60 * index + 'px' ;
                }) ;
            }
        },
        // 事件绑定方法
        on : function(ele, type, fn) {
            ele.addEventListerner ? ele.addEventListerner(type, fn, false) : ele.attachEvent('on' + type, fn) ;
            return this ;
        }
    }



    /**
    *   案例三:图片的延迟加载,方式一:初始
    */
    /***
    *   节流延迟加载图片类
    *   @param  id      延迟加载图谱的容器id
    *   注:图片格式如下<img src = 'img/loading.gif' alt = '' data-src = 'img/1.jpg'>
    ****/
    function LazyLoad(id) {
        // 获取需要节流延迟加载图片的容器
        this.container = document.getElementById(id) ;
        // 缓存图片
        this.imgs = this.getImgs() ;
        // 执行逻辑
        this.init() ;
    }
    // 节流延迟加载图片类原型方法
    LazyLoad.prototype = {
        // 起始执行逻辑
        init : function(){
            // 加载当前视图图片
            this.updata() ;
            // 绑定事件
            this.bindEvent() ;
        },
        // 获取延迟加载图片
        getImgs : function() {
            // 新数组容器
            var arr = [] ;
            // 获取图片
            var imgs = this.container.getElementgTagName('img') ;
            // 将获取的图片转化为数组(IE下通过Array.prototype.slice会报错)
            for(var i = 0; i < imgs.length; i++) {
                arr.push(imgs[i]) ;
            }
            return arr ;
        },
        // 加载图片
        updata : function() {
            // 如果图片都加载完成,返回
            if(!this.imgs.length) {
                return ;
            }
            // 获取图片长度
            var i = this.imgs.length ;
            // 遍历图片
            for(--i; i >= 0; i--) {
                // 如果图片在可视范围内
                if(this.shouldShow(i)) {
                    // 加载图片
                    this.imgs[i].src = this.imgs[i].getAttribute('data-src');
                    // 清除缓存中的此图片
                    this.imgs.splice(i, 1) ;
                }
            }
        },
        // 判断图片是否在可视范围内
        shouldShow : function(i) {
            // 获取当前图片
            var img = this.imgs[i] ;
            // 可视范围内顶部高度(页面滚动条top值)
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop ;
            // 可是范围内底部高度
            var scrollBottom = scrollTop + document.documentElement.clientHeight ;
            // 图片的顶部位置
            var imgTop = this.pageY(img) ;
            // 图片的底部位置
            var imgBottom = imgTop + img.offsetHeight ;
            // 判断图片是否在可视范围内:图片底部高度大于可视试图顶部高度并且图片底部高度小于可视试图底部高度,或者图片顶部高度大于可视试图顶部高度并且图片顶部高度小于可视试图底部高度
            if(imgBottom > scrollTop && imgBottom < scrollBottom || (imgTop > scrollTop && imgTop < scrollBottom)) {
                return true ;
            }
            // 不满足上面条件则返回false
            return false ;
        },
        // 获取元素页面中的纵坐标位置
        pageY : function(element) {
            // 如果元素有父元素
            if(element.offsetParent) {
                // 返回元素 + 父元素高度
                return element.offsetTop + this.pageY(element.offsetParent) ;
            }else {
                return element.offsetTop ;
            }
        },
        // 绑定事件(简化版)
        on : function(element, type, fn) {
            if(element.addEventListerner) {
                addEventListerner(type, fn, false) ;
            }else {
                element.attachEvent('on' + type, fn, false) ;
            }
        },
        // 为窗口绑定resize事件和scroll事件
        bindEvent : function() {
            var that = this ;
            this.on(window, 'resize', function() {
                // 节流处理更新图片逻辑
                throttle(that.updata, {context : that}) ;
            }) ;
            this.on(window, 'scroll', function() {
                //节流处理更新图片逻辑
                throttle(that.updata, {context : that}) ;
            }) ;
        }
    }
    // 测试用例:
    // 延迟加载container容器内的图片
    new LazyLoad('container') ;


    /**
    *   案例四:统计打包,方式一:初始
    */
    // 打包统计对象
    var LogPack = (function() {
        // 请求缓存数组
        var data = [] ;
        // 请求缓存最大值
        var MaxNum = 10 ;
        // 统计项统计参数间隔符
        var itemSplitStr = '|' ;
        // 统计项统计参数键值对间隔符
        var keyValueSplitStr = '*' ;
        // 请求触发器,通过图片src属性实现简单的get请求
        var img = new Image() ;
        // 发送请求方法
        function sendLog() {
            // 请求参数
            var logStr = '' ;
            // 截取MaxNum个统计项发送
            fireData = data.splice(0, MaxNum) ;
            // 遍历统计项
            for(var i = 0; i < fireData.length; i++) {
                // 添加统计项顺序索引
                logStr += 'log' + i + '=' ;
                // 遍历统计项内的统计参数
                for(var j in fireData[i]) {
                    // 添加统计项参数键 + 间隔符 + 值
                    logStr += j + keyValueSplitStr + fireData[i][j] ;
                    // 添加统计项统计参数间隔符
                    logStr += itemSplitStr ;
                }
                // &符拼接多个统计项
                logStr = logStr.replace(/|$/, '') + '&' ;
            }
            // 添加统计项打包长度
            // logStr += 'logLengthh=' + len ;
            logStr += 'logLengthh=' + fireData.length ;
            // 请求触发器发送统计
            img.src = 'a.gif' + logStr ;
        }
        // 统计方法
        return function(param) {
            // 如果无参数则发送统计
            if(!param) {
                sendLog() ;
                return ;
            }
            // 添加统计项
            data.push(param) ;
            // 如果统计项大于请求缓存最大值则发送统计请求包
            data.length >= MaxNum && sendLog() ;
        }
    })() ;

    // 测试统计

    // 点击统计
    document.getElementById('btn').onclick = function() {
        LogPack({
            btnId : this.id,
            context : this.innerHTML,
            type : 'click'
        }) ;
    } ;

    // 点击统计
    document.getElementById('btn').onmouseover = function() {
        LogPack({
            btnId : this.id,
            context : this.innerHTML,
            type : 'mouseover'
        }) ;
    } ;
</script>    

</body>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值