經驗總結:按需加載JS和css


項目中做過這樣的事情:所有頁面都通過SSI指令 include這樣一份public-js.shtml, 用來引入涉及到的js(包括公共的腳本 驗證插件 自定義組件等),但是一些沒有交互效果的頁面根本不需要用到這些腳本,所以造成腳本冗余較大(盡管可以從緩存讀取,但還是應該盡量減少沒用到的腳本為佳)

public-js.shtml

<!--#config timefmt="%Y%m%d%H%M%S"-->
<script type="text/javascript" src="/js/jquery1.6.js?v=<!--#flastmod virtual='/js/jquery1.6.js' -->" ></script>
<!-- <script type="text/javascript" src="/js/core.js?v=#flastmod virtual='/js/core.js'" ></script>
-->
<script type="text/javascript" src="/js/public.js?v=#flastmod virtual='/js/public.js'" ></script>

<!-- 加載組件 -->

<!--#include virtual="/include/component.shtml" -->

<!-- 加載表單驗證插件 -->
<!--#include virtual="/include/nicevalidator.shtml" -->

<!-- 頁面通用函數 -->
<!--#include virtual="/include/page-js.shtml" -->

 

為了實現組件和驗證插件的按需加載,定義這么一個函數loadJsCss

/*** js和css按需加載 ***/
function loadJsCss(url, callback ){// 非阻塞的加載 后面的js會先執行
    var isJs = /\/.+\.js($|\?)/i.test(url) ? true : false;
    function onloaded(script, callback){//綁定加載完的回調函數
        if(script.readyState){ //ie
            script.attachEvent('onreadystatechange', function(){
                if(script.readyState == 'loaded' || script.readyState == 'complete'){
                    script.className = 'loaded';
                    callback && callback.constructor === Function && callback();
                }
            });
        }else{
            script.addEventListener('load',function(){
                script.className = "loaded";
                callback && callback.constructor === Function && callback();
            }, false); 
        }
    }
    if(!isJs){ //加載css
        var links = document.getElementsByTagName('link');
        for(var i = 0; i < links.length; i++){//是否已加載
            if(links[i].href.indexOf(url)>-1){ 
                return; 
            }
        }
        var link = document.createElement('link');
        link.type = "text/css";
        link.rel = "stylesheet";
        link.href = url;
        var head = document.getElementsByTagName('head')[0]; 
        head.insertBefore(link,head.getElementsByTagName('link')[0] || null );
    }else{ //加載js
        var scripts = document.getElementsByTagName('script');
        for(var i = 0; i < scripts.length; i++){//是否已加載
            if(scripts[i].src.indexOf(url)>-1 && callback && (callback.constructor === Function) ){ 
            //已創建script
                if(scripts[i].className === 'loaded'){//已加載
                    callback();
                }else{//加載中
                    onloaded(scripts[i], callback);
                }
                return; 
            }
        }
        var script = document.createElement('script');
        script.type = "text/javascript";
        script.src = url; 
        document.body.appendChild(script);
        onloaded(script, callback); 
        
    }
}

// 表單驗證插件 動態加載
function loadValidator(callback){// 加載nicevalidator插件
loadJsCss("/css/nicevalidator.css");
loadJsCss("/js/nicevalidator.js", callback);
}

 
         

// 組件動態加載
function loadComponent(callback){// 加載自定義組件
loadJsCss("/css/component.css");
loadJsCss("/js/component.js", callback);
}

 

但是發現每個驗證方法或組件的調用都要放到回調函數內部,實在笨拙,而且改起來也很麻煩。如:

loadValidator(function(){ $('#frm').validator({...}););

loadComponent(function(){ $.Tab({...}); );

 

經過嘗試發現可以保持頁面原有的調用方式,只需在public.js公共js文件中定義相同接口即可:

(function(){
    $.fn.validator = function(){
        var args = arguments, self = this;
        loadValidator(function(){//~~~初始狀態fn.validator會請求js和css, 加載后的回調函數重寫 fn.validator 為正確的方法
            $.fn.validator.apply(self, args);
        })
    }
    var fnames = ['Tab',"SiceSlider","SiceLvSelect","SiceSelect"];
    $.each(fnames, function(i,fname){//~~~同理 回調函數重寫接口為正確的函數
        $[fname] = function(){
            var args = arguments;

            loadComponent(function(){ 
                var Foo = function(){}; Foo.prototype = $[fname].prototype; var foo = new Foo(); // 需要new 的組件,這樣獲取參數對象
                $[fname].apply(foo,args);  
            });
        }
    });
})(jQuery)

~~~個人認為在不用seaJs requireJs等模塊化管理插件的情況下,這種方式也還可以。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM