zoukankan      html  css  js  c++  java
  • javascript设计模式实践之代理模式--图片预加载

    图片的预加载就是在加载大图片前,先显示一个loading.gif,就算在网络比较慢的时候也能让人知道正在加载,总比啥反应都没有强。

    下面这段代码就是预加载的一个简单的实现,假设先不处理加载图片时的onError,onAbort,超时的问题。

    只关注代码的结构。

    复制代码
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
        </head>
        <body>
            <button id='btnLoadImg'>加载图片</button>
            <br>
            <div id='imgContainer'>
            </div>
            <br>
    
            <script type='text/javascript' src="./jquery-1.11.3.min.js"></script>
            <script type='text/javascript'>
                $(document).ready(function(){
                    $('#btnLoadImg').bind('click', doLoadImg);
                });
    
                function doLoadImg(){
    
                    var eleImg = createImgElement();
                    document.getElementById('imgContainer').appendChild(eleImg);
    
                    loadImg(eleImg, 'http://img.wanchezhijia.com/A/2015/3/20/17/11/de63f77c-f74f-413a-951b-5390101a7d74.jpg');
                }
    
                //创建img标签
                //这里用自执行函数加一个闭包,是为了可以创建多个id不同的img标签。
                var createImgElement = (function(){
                    var index = 0;
    
                    return function() {
                        var eleImg = document.createElement('img');
                        eleImg.setAttribute('width', '200');
                        eleImg.setAttribute('heght', '150');
                        eleImg.setAttribute('id', 'img' + index++);
                        return eleImg;
                    };
                })();
    
                //预加载图片
                //给img标签设一个加载图片,通过Image对象预先加载实际图片加载完成后设到img标签上
                function loadImg(img, src) {
                    var imgCache = new Image();
                    imgCache.onload = function(){
                        img.src = this.src;
                    };
    
                    img.src = 'loading.gif';
                    imgCache.src = src;
                }
    
            </script>
        </body>
    </html>
    复制代码

    以下预加载的代码功能上是满足了,但是它的职责包含了预加载和加载两个职责,违反了“单一职责原则”。所谓的职责就是“会发生的变化”,如果网速的 问题不再是问题或者加载的图片的分辨率被控制在很小的时候等,需要去掉预加载的功能,这时候就要修改loadImg的代码,就要重新跑所有相关的测试,即 违反了“开闭原则”,又增加测试工作。

    复制代码
                function loadImg(img, src) {
                    var imgCache = new Image();
                    imgCache.onload = function(){
                        img.src = this.src;
                    };
    
                    img.src = 'loading.gif';
                    imgCache.src = src;
                }
    复制代码

    加载和预加载其实就是代理模式的一种,代理模式可以理解成,你会开车但是因为某种原因只能找人代理开车,因为不了解MM的喜好找人代理送花。

    将预加载功能改成代理模式可以理解成:本体先显示个门面,找代理去加载,加载完了,告诉本体,本体把图片贴上去就行了。

    既然如此,本体的职责就很简单了,就往门面上贴。

    加载本体函数:

                function loadImg(img, src) {
                    img.src = src;
                }

    做一个预加载代理函数:

    复制代码
                function loadImgProxy(img, src){
                    var imgCache = new Image();
                    imgCache.onload = function(){
                        loadImg(img, this.src);
                    };
    
                    loadImg(img, 'loading.gif');
                    imgCache.src = src;
                }
    复制代码

    在代理函数中,先让本体加载loading.gif,等大图加载完了再让本体加载实际图片。

    代理还是和本体函数的接口参数是一致的,职责分的比较清晰,如果到时候要把预加载去掉,也不需要修改本体和代理的代码,只需要在调用的地方把代理的名字换成本体的名字即可。

    可以适当的把代理函数改一下,可以让其适应加载多个图片的场景,其实就是做一个闭包,把缓存Image对象变成私有即可:

    复制代码
                var loadImgProxy = (function(){
                    var imgCache = new Image();
    
                    return function(img, src){
                        imgCache.onload = function(){
                            loadImg(img, this.src);
                        };
    
                        loadImg(img, 'loading.gif');
                        imgCache.src = src;
                    };
                })();
    复制代码

    修改后的完整代码:

    复制代码
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
        </head>
        <body>
            <button id='btnLoadImg'>加载图片</button>
            <br>
            <div id='imgContainer'>
            </div>
            <br>
    
            <script type='text/javascript' src="./jquery-1.11.3.min.js"></script>
            <script type='text/javascript'>
                $(document).ready(function(){
                    $('#btnLoadImg').bind('click', doLoadImg);
                });
    
                function doLoadImg(){
    
                    var eleImg = createImgElement();
                    document.getElementById('imgContainer').appendChild(eleImg);
    
    //使用代理函数进行加载
    //如果某一天不需要预加载了,就把loadImgProxy换成loadImg即可 loadImgProxy(eleImg, 'http://img.wanchezhijia.com/A/2015/3/20/17/11/de63f77c-f74f-413a-951b-5390101a7d74.jpg'); } //创建img标签 //这里用自执行函数加一个闭包,是为了可以创建多个id不同的img标签。 var createImgElement = (function(){ var index = 0; return function() { var eleImg = document.createElement('img'); eleImg.setAttribute('width', '200'); eleImg.setAttribute('heght', '150'); eleImg.setAttribute('id', 'img' + index++); return eleImg; }; })();
    //加载图片本体函数 function loadImg(img, src) { img.src = src; }
    //加载图片代理函数 var loadImgProxy = (function(){ var imgCache = new Image(); return function(img, src){ imgCache.onload = function(){ loadImg(img, this.src); }; loadImg(img, 'loading.gif'); imgCache.src = src; }; })(); </script> </body> </html>
    复制代码
  • 相关阅读:
    LeetCode 79. 单词搜索
    LeetCode 1143. 最长公共子序列
    LeetCode 55. 跳跃游戏
    LeetCode 48. 旋转图像
    LeetCode 93. 复原 IP 地址
    LeetCode 456. 132模式
    LeetCode 341. 扁平化嵌套列表迭代器
    LeetCode 73. 矩阵置零
    LeetCode 47. 全排列 II
    LeetCode 46. 全排列
  • 原文地址:https://www.cnblogs.com/koleyang/p/4939813.html
Copyright © 2011-2022 走看看