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>
    复制代码
  • 相关阅读:
    Vue.js实现的计算器功能完整示例
    vue实现简易计算器
    Vuex中mutations与actions的区别详解
    两个子组件之间的传值
    JS操作元素节点(非常详细)
    js包装类
    Vue Router 的params和query传参的使用和区别(详尽)
    初步了解生命周期
    简单介绍一下Progressive Web App(PWA)
    webpack学习笔记(阮一峰教程demo)
  • 原文地址:https://www.cnblogs.com/koleyang/p/4939813.html
Copyright © 2011-2022 走看看