天天看点

支持seaJs和requireJs的前端模块开发方案(二):业务页面和入口脚本init.js一.业务页面二.入口脚本init.js

前言

前一篇文章已经对方案的基本作用、目录要求已经做了说明,请务必先阅读。

本文将对业务页面以及业务页面需要引入的唯一脚本init.js进行讲解,同时贴出全部代码,代码不做详细的讲解,有不懂的可以留言提问。

一.业务页面

业务页面即入口页面有两种模式,一种为自动模式,该模式根据钩子调用init.js脚本,实现异步串行加载业务页面所需的所有脚本文件;一种为手动模式,手动模式即手动引入页面所需的所有脚本文件,业务脚本代码可放在页面中。

自动模式:

<script type="text/javascript">
      /*var static_url = 'http://localhost:8862';*/
    </script>
    <script id="ENTRY" data-type="amd" data-app="amd-requireJs-demo" data-module="" data-page="login" src="http://localhost:8861/static/init.js"></script>
           
  • static_url变量为静态资源域,如不设置和设置为空,则自动为当前业务页面使用的域;
  • 引入init.js文件的代码中设置了一个id和4个data标签,分别作用为:
    • id="ENTRY"  入口脚本的标识,不可变,用于识别当前页面是否使用自动模式;
    • data-type="amd"  加载器模式,可选amd或者cmd,分别代码了requireJs和seaJs;
    • data-app="amd-requireJs-demo"  当前页面所属的app名,或者app下的某个系统单元(当把方案作为某一个app时);
    • data-module=""  当前页面所属app的系统单元,设置为空时代表没有细分系统单元;
    • data-page="login"  当前面的业务脚本名,省略".js"后缀;
  • 调试查看的效果为:
    支持seaJs和requireJs的前端模块开发方案(二):业务页面和入口脚本init.js一.业务页面二.入口脚本init.js

手动模式:

<script src="http://localhost:8861/static/libs/amd/require/2.2.0/require.min.js"></script>
<script src="http://localhost:8861/static/alias.js"></script>
<script src="http://localhost:8861/static/apps/amd-requireJs-demo/js/config.js"></script>
<script type="text/javascript">
require(['jquery','global'], function ($,gloabl) {
    console.log('非自动');
    var val = $('input[name="seller_name"]').val();
    $('input[name="seller_name"]').val(val+'--');
    console.log("login.js--->我是入口脚本,成功获取到了本页的标题:"+document.title);
});
</script>
           

手动模式就不过多讲解,和常规写法一致。

二.入口脚本init.js

脚本主要对实现2个功能:抛出自动模式下的全局变量、实现异步串行加载所需JS文件。

window.ENTRY_CONF = window.ENTRY_CONF || {
    // web域,自动获取当前域
    SITE_URL: document.location.protocol + "//" + location.hostname + (location.port ? ":" + location.port : "") + "/",
    // 页面运行开始时间
    STIME: new Date().getTime(),
    //识别节点
    NODE: document.getElementById("ENTRY"),
    // 是否自动加载JS
    AUTO_LOAD_SCRIPTS: function() {
        return this.NODE !== null ? true : false; 
    },
    // 提取架构方式
    TYPE: function() {
        var tp = this.NODE.getAttribute("data-type");
        if (tp === 'cmd' || tp === 'CMD') return 'cmd';
        else if (tp === 'amd' || tp === 'AMD') return 'amd';
    },
    // 当前所属应用标识
    APP: function() {
        var app = this.NODE.getAttribute("data-app")
        return app === '' || app === null ? '' : "apps/" + app + '/';
    },
    // 当前所属应用下的系统模块
    MODULE: function() {
        var mod = this.NODE.getAttribute("data-module")
        return mod === '' || mod === null ? 'js/' : mod + '/js/';
    },
    // 当前所属应用下的系统模块
    PAGE: function() {
        var page = this.NODE.getAttribute("data-page")
        return page === '' || page === null ? '' : '/' + page;
    },
    // static资源域,优先获取页面定义的static_url
    SITE_STATIC_URL: function() {
        return 'undefined' === typeof static_url || '' === static_url ? this.SITE_URL : static_url + "/"; 
    },
    // 静态资源目录,当SITE_STATIC_URL为web域时使用
    STATIC_FOLDER: function() {
        return this.SITE_STATIC_URL() === this.SITE_URL ? this.SITE_STATIC_URL() + 'static/' : this.SITE_STATIC_URL(); 
    },
    // 第三方资源目录细化路径  LIBS_FOLDER
    LIBS_FOLDER: function() {
        if (this.TYPE() === 'cmd') return this.STATIC_FOLDER() + 'libs/';
        else if (this.TYPE() === 'amd') return this.STATIC_FOLDER() + 'libs/';
    },
    // 自有资产目录细化路径
    ASSETS_FOLDER: function() {
        return this.STATIC_FOLDER() + 'assets/js/'; 
    },
    // 是否合并资源
    COMBO: false
};
//资源路径(全局)
var _LIBSURL = ENTRY_CONF.LIBS_FOLDER()+ENTRY_CONF.TYPE()+'/';
var _ASSETSURL = ENTRY_CONF.ASSETS_FOLDER()+ENTRY_CONF.TYPE()+'/';
var _SYSTEMURL = ENTRY_CONF.STATIC_FOLDER() + ENTRY_CONF.APP() + ENTRY_CONF.MODULE();
           

上面代码中定义了一些全局变量,并且抛出了3个资源路径变量分别为:_LIBSURL、_ASSETSURL、_SYSTEMURL,这3个变量代表了第三方公共资源目录、私有公共资源目录、app系统或系统下模块的资源目录。

接下来就是实现异步串行加载所需JS文件,代码如下:

// 入口
var entry = function() {
    if (!ENTRY_CONF.AUTO_LOAD_SCRIPTS()) {
        return false;
    }
    this.stime = ENTRY_CONF.STIME;
    this.staticFolder = ENTRY_CONF.STATIC_FOLDER();
    this.labsFolder = ENTRY_CONF.LIBS_FOLDER();
    this.combo = ENTRY_CONF.COMBO;
    this.type = ENTRY_CONF.TYPE();
    this.app = ENTRY_CONF.APP();
    this.module = ENTRY_CONF.MODULE();
    this.page = ENTRY_CONF.PAGE();
    this.init();
};
entry.prototype.init = function() {
    var self = this;
    var scripts = self.getScripts();
    self.seriesLoadScripts(scripts, function() {
        return self.callback();
    });
};
entry.prototype.getScripts = function() {
    var self = this,
        loaderJs,
        comboJs,
        loaderAliasJs,
        loaderConfigJs,
        pageJs;
    //加载器脚本 及 合并辅件
    if (self.combo) {
        if (self.type === 'cmd' || self.type === 'CMD') {
            publicUrl = self.staticFolder + "/??",
            loaderJs = publicUrl + "libs/cmd/seajs/seajs/2.1.1/sea.js"; //加载器脚本
            comboJs = ",libs/cmd/seajs/seajs-combo/1.0.1/seajs-combo.js"; //加载器脚本
            loaderAliasJs = ",alias.js"; //总配置脚本
            loaderConfigJs = "," + self.app + self.module + 'config.js'; //模块配置脚本
            pageJs = "," + self.app + self.module + self.page + '.js'; //业务脚本
            return [loaderJs + comboJs + loaderAliasJs + loaderConfigJs + pageJs]; //返回arr
            //demo->http://localhost:8861/static//??libs/cmd/seajs/seajs/2.1.1/sea.js,alias.js,apps/app2/js/config.js,apps/app2/js/login.js
        } else {
            console.log("requireJs无法自动合并模块路径,请关闭combo或改用cmd模式")
            return false;
        }
    } else {
        //加载器脚本
        if (self.type === 'cmd' || self.type === 'CMD') loaderJs = self.labsFolder + "cmd/seajs/seajs/2.1.1/sea.js";
        else if (self.type === 'amd' || self.type === 'AMD') loaderJs =  self.labsFolder + "amd/require/2.2.0/require.min.js";
        loaderAliasJs = self.staticFolder + "alias.js"; //总配置脚本
        loaderConfigJs = self.staticFolder + self.app + self.module + 'config.js'; //模块配置脚本
        pageJs = self.staticFolder + self.app + self.module + self.page + '.js'; //业务脚本
        return [loaderJs, loaderAliasJs, loaderConfigJs, pageJs]; //返回arr
    }
};
entry.prototype.seriesLoadScripts = function(scripts, callback) {
    if (typeof(scripts) != "object") var scripts = [scripts];
    var s = new Array(),
        last = scripts.length - 1,
        recursiveLoad = function(i) {
            s[i] = document.createElement("script");
            s[i].setAttribute("src", scripts[i]);
            s[i].onload = s[i].onreadystatechange = function() {
                if (! /* @[email protected] */ 0 || this.readyState == "loaded" || this.readyState == "complete") {
                    this.onload = this.onreadystatechange = null;
                    if (i !== last) recursiveLoad(i + 1);
                    else if (typeof(callback) === "function") callback();
                }
            }
            document.body.appendChild(s[i]);
        };
    recursiveLoad(0);
};
entry.prototype.callback = function() {};
//启用
new entry();
           

以上代码根据页面设置的钩子信息和window.ENTRY_CONF配置,异步串行加载了页面所需的脚本。在使用seaJs作为加载器时,有一个combo配置,开通的话会自动书写合并形式如“http://localhost:8861/static//??libs/cmd/seajs/seajs/2.1.1/sea.js,alias.js,apps/app2/js/config.js,apps/app2/js/login.js”;但是用requireJs作为加载器时无法自动进行合并,因为require.js配套的r.js辅件需要node环境,但是seaJs配套的combo.js则为自动将模块间的引用进行合并。