seajs模块化改造实践

前言

一月份的时候,临近放假,拿到一个需求,新增一个产品,我一个前端对一个java后端,两个星期的开发时间。 因为大部分功能在别的产品都已经有了,基本都是简单处理一下拿过来,再添加一下额外需要的功能,比如选择出行国家等。前一天拿到文档看了下,搞清楚之后,第二天开工,基本一天就把功能做完了。这一天的大部分时间还是花在-找代码上。无他,实在是遗留的代码 不是很清晰。

因为系统比较旧,前后端也没有分离,jsp的,代码也很混乱,逻辑里面还有很多奇怪的注释,在这些上面做了很多无用功。 基本做好功能,联调测试,通过之后基本就OK了。

但是两个周的时间才用了两三天。还有十来天呢,怎么办呢,看着这些混乱的代码,本着造福别人,也为以后的方便,就想着,用模块重新组织一下吧。因为去年有过这方面经验,轻车熟路。所以,就有了后来的故事和今天的这篇文字。

改造前

改造前的代码大概是这个样子的:

        <link href="../mobileSinglePlatform/css/miuiall.css" type="text/css" rel="stylesheet">
        <link href="../mobileSinglePlatform/css/miuitraffic.css" type="text/css" rel="stylesheet">
        <link href="../mobileSinglePlatform/css/mobiscroll.core-2.5.2.css" rel="stylesheet" type="text/css" />
        <script src="../mobileSinglePlatform/js/jquery-1.8.2.min.js" type="text/javascript"></script>
        <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
        <script src="../mobileSinglePlatform/js/common.js" type="text/javascript"></script>
        <script src="../mobileSinglePlatform/js/dateUtil.js" type="text/javascript"></script>
        <script src="../mobileSinglePlatform/js/ahsInsuranceForGroup_1.js" type="text/javascript"></script>
        <script src="../mobileSinglePlatform/js/mobiscroll.core-2.5.2.js" type="text/javascript"></script>
        <script src="../mobileSinglePlatform/js/mobiscroll.core-2.5.2-zh.js" type="text/javascript"></script>
        <script src="../mobileSinglePlatform/js/mobiscroll.datetime-2.5.1.js" type="text/javascript"></script>
        <script src="../mobileSinglePlatform/js/mobiscroll.datetime-2.5.1-zh.js" type="text/javascript"></script>
        <script src="../mobileSinglePlatform/js/jquery.form.js" type="text/javascript"></script>
        <script type="text/javascript" src="../mobileSinglePlatform/js/commonTools.js"></script>
        <script type="text/javascript" src="../mobileSinglePlatform/js/getOpenId.js"></script>
        <script type="text/javascript" src="../mobileSinglePlatform/js/wechatUtil.js"></script>
        <script src="//www.pingan.com/app_js/sdc/prd/sdc9_m.js"> </script>
        <script src="../mobileSinglePlatform/js/webtrends.js"></script>
        <script type="text/javascript">
        initWebtrends();
        </script>


        <c:if test="${not empty productDetail.specialPromise}">
            <tr>
            <td colspan="2">
            </td>
            </tr>
            <tr>
            <th width="60%" align="left">特别约定</th>
            <th width="40%" align="right">&nbsp;</th>
            </tr>
            <tr>
            <td colspan="2">
            <div id="specialInsurance" class="specialInsurance">
            <div id="specialInsurancener">
            <c:out value="${productDetail.specialPromise}"/>
            </div>
            </div>
            <div id="readmore" class="specialInsurance" style="margin-top:3%;">
            </div>
            </td>
            </tr>
        </c:if>
        <c:choose>
            <c:when test="${not empty discountAmount}">
                <tr>
                <td colspan="2">
                <!--#=保费-->
                <div class="left fsize03 fwight" style="margin-top:20px;">标准保费&nbsp;<del datetime="20150428"><font
                id="fontColor"><span id="amount"><c:out value="${AMOUNT }"/></span>元/人</font></del></div>
                </td>
                </tr>
                <tr>
                <td colspan="2">
                <!--#=保费优惠价-->
                <div class="left fsize03 fwight" style="margin-top: 5px;color: #F00;padding: 5px 0px">优惠价&nbsp;<span
                id="standardAmount"><c:out value="${discountAmount }"/></span>元/人</div>
                </td>
                </tr>
            </c:when>

不多贴代码了,大概就是这个样子的。这种情况的原因大概是:

1.起初的页面是后端人员写的,没有很好的组织各种资源。写到一定数量之后,各种逻辑已经耦合在一起,别的人接手之后,又不敢乱改,就按以前的做法复制粘贴,做好自己的那一块。久而久之,页面就越来越复杂,冗余也越来越多,形成了一个恶性循环。

2.网络环境不允许。使用公司标配的联想笔记本,标装之后,收到公司安全策略的限制,很多技术网站无法访问,查资料有时候只能看百度快照,有些同事只好用手机或者自带电脑来解决这个问题。至于 github,google,基本是不可能的。

3.没有代码规范。基本每个人都是按照自己的风格来,最后归并之后的代码就显得很混乱。

由于不能使用脚手架自动化工具,这种情景要做模块化,requireJs/seaJs 是比较好的选择。去年用过requireJs,这次就用一下seaJs.

由于项目中的样式文件实在太多太杂,时间上不允许我重新组织一遍,所以就只对逻辑代码做了模块化处理。

组织模块

要组织模块,首先要弄清楚相应的规则。最好的方式当然是看 seajs文档 了.

这里也简单介绍下几个常用的功能。

    
    // 页面中包括的js
    <script src="./js/seajs/2.3.0/sea.js" id="seajsnode" ></script>
    <!-- 
        加上 seajsnode 值,可以让 sea.js 直接获取到自身路径,而不需要通过其他机制去自动获取。
        这对性能和稳定性会有一定提升,推荐默认都加上。
     -->

    <script src="./js/config-seajs.js" ></script>
    <!--配置项 -->

    <script type="text/javascript">
            seajs.use('main');
            /*
                seajs.use 理论上只用于加载启动,不应该出现在 define 中的模块代码里。
                在模块代码里需要异步加载其他模块时,推荐使用 require.async 方法。
            */
    </script>

再看一下配置信息:

    seajs.config({
    base:"./js/",
    paths: { //当目录比较深,或需要跨目录调用模块时,可以使用 paths 来简化书写。 
           "seajs": "seajs/2.3.0/sea.js"
    },
    alias:{ // 设置别名,方便调用 , 当模块标识很长时,可以使用 alias 来简化。
        "jquery" : "lib/jquery/1.10.0/jquery.min.js",
        'Hello':'mod/mod4.js',
    },
    map: [
        [".js",".js?1.0"]
    ],
    debug:true //值为 true 时,加载器不会删除动态插入的 script 标签。插件也可以根据 debug 配置,来决策 log 等信息的输出。
});

然后是页面入口:

//main.js

/*
    define define(factory)

    define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串。

    factory 为对象、字符串时,表示模块的接口就是该对象、字符串。比如可以如下定义一个 JSON 数据模块:

    define({ "foo": "bar" });
    也可以通过字符串定义模板模块:

    define('I am a template. My name is {{name}}.');
    factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module:

    define(function(require, exports, module) {

      // 模块代码

    });
*/
define(function (require, exports, module) {

    var $ = require('jquery');
    
    console.log($); 
            
    require('mod1');
    
    var Hello = require('Hello');
    
        Hello.init();
        
        
    // other code...
        
});

看一下模块内的代码:

//mod1.js
    define(function (require, exports, module) {
        console.log('mod1加载完毕');
});
//mod4.js
define('Hello',function(require,exports, module) {

    var Hello = {
            sayHello:function(){
                console.log('hello');
            }  
    }

    module.exports = Hello;
});

打开页面控制台,就会看到输出的信息:

clipboard.png

说明我们的模块已经被成功的被加载了。

当然 实际的工作中还要用到各种插件,这就需要知道如何改造现有文件为 CMD 模块

这些在文档中都能找到。

以上简单介绍了使用seajs 组织模块的方法。

当然,模块写完之后呢,我们还需要相应的构建工具。

玉伯说:

如果使用 Sea.js,强烈推荐采用配套的构建工具来压缩、合并代码。如果不这么做,可能会带来不少额外的工作甚至隐患。

如果不合并代码,也能运行,你会看到你的插件代码都会以async的方式插入到页面的头部。而且需要你手动处理依赖关系,也产生了额外的请求,不是很友好。如下图:

clipboard.png

所以,为了避免意外的发生,也为了减少请求数,应该合并模块。

我们来看一个实际的例子-支付宝的登陆页面。

在网页支付宝收银台中的运用

clipboard.png

![clipboard.png]
clipboard.png

clipboard.png

很直观的就能看到插模块的合并,这个合并的工作就是构建工具的功劳了。

我们也来实现一下。

先看效果吧,执行模块合并之后,入口文件可以是这样的:

clipboard.png

这样就实现了模块的打包合并。

我这里使用了gulp来实现这一步, 代码如下:

//seajs合并模式
gulp.task("seajs", function () {
    return merge(
        gulp.src(src + '/js/!(lib)/**/*.js', {base: src + '/js'})
            .pipe(transport())
            .pipe(concat({
                base: src + '/js'
            }))
            .pipe(replace({
                patterns: replace_patterns
            }))
            .pipe(gulp.dest(dist + '/js')),

        gulp.src([src + '/js/lib/**/*.js', src + '/js/common.js'], {
                base: src + '/js'
            })
            .pipe(replace({
                patterns: replace_patterns
            }))
            .pipe(gulp.dest(dist + '/js'))
    );
});

使用gulp提取模块有其他更详细的教程,这里提供一个我认为比较好的:

介绍一种基于gulp对seajs的模块做合并压缩的方式

那个支付宝的登陆页 这里给出完整代码,给大家观摩:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
<meta name="renderer" content="webkit"/>
<title>支付宝快捷收银台</title>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta name="format-detection" content="telephone=no,email=no"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"/>
<link rel="apple-touch-icon" href="https://i.alipayobjects.com/i/ecmng/png/201406/2qBuceUYiL.png" />
<link rel="apple-touch-icon-precomposed" href="https://i.alipayobjects.com/i/ecmng/png/201406/2qBuceUYiL.png" />
<!-- CMS:安全支付客户端网关/common/tracker.vm开始:common/tracker.vm -->


<!-- CMS:安全支付客户端网关/common/tracker.vm结束:common/tracker.vm --><script charset="utf-8" src="https://as.alipayobjects.com:443/g/snake/h5cashier/1.0.5/h5cashier.js"></script>
<link rel="stylesheet" type="text/css" href="https://as.alipayobjects.com:443/g/snake/h5cashier/1.0.5/h5cashier.css" media="all" />
<script charset="utf-8" id="seajsnode" src="https://a.alipayobjects.com:443/??seajs/seajs/2.2.0/sea.js,seajs/seajs-combo/1.0.0/seajs-combo.js"></script>

<script>
    seajs.config({
        alias: {
            '$': 'gallery/zepto/1.0.2/zepto',
            'validator': 'arale/validator/0.9.7/validator',
            'widget': 'arale/widget/1.1.1/widget',
            'base': 'arale/base/1.1.1/base',
            'class': 'arale/class/1.1.0/class',
            'events': 'arale/events/1.1.0/events',
            'wapcashier': 'mobileclientgw/wapcashier/1.1.7/wapcashier'
        },
        vars: {
            locale: 'zh-cn'
        }
    });
</script>
</head>
<body>
<div class="J-msg-mask am-msg-mask" style="display:none"></div>
<div class="J-msg-box am-msg-box" style="display:none">
    <div class="am-msg-box-content">
        <p class="J-msg-text"></p>
        <button class="J-msg-cancel am-button am-button-blue" type="button">知道了</button>
    </div>
</div>


    <div class="J-loading am-loading"><div class="am-loading-text">加载中...</div></div>

<!-- CMS:安全支付客户端网关/common/notice.vm开始:common/notice.vm --><!-- CMS:安全支付客户端网关/common/notice.vm结束:common/notice.vm -->


<!-- cashierLoginNew.vm -->



            
<!-- v5_need_login_new -->
<script>window.Tracker && Tracker.click('v5_need_login_new')</script>


<header class="am-header">
    <h1>
        <span class="title-main" data-title="登录支付宝">登录支付宝</span>    </h1>
                                                        <a href="#" class="J-back J-header-back am-header-reverse am-header-reverse-icon" seed="v5_need_login_new-back"><i class="icon icon-arrow-back"></i><span>返回</span></a>
                        
    </header>


<noscript><h1 style="color:red">您的浏览器不支持JavaScript,请更换浏览器或开启JavaScript设置!</h1></noscript>
<style>
    h5 {
        overflow: hidden;
    }
    .am-content h5.am-ft-mb-20 {
        margin-bottom: 20px;
    }
</style>
<div class="am-content">
    <form id="cashier" action="https://mclient.alipay.com/h5/loginIdPwdLogin.htm?awid=RZ117V8UyX8dVXb9l8WaAkSdN6nF7kmobileclientgwRZ11" method="post">
        <!-- 禁止浏览器自动填充账户名密码 -->
        <input style="display:none" type="text" name="fakeusernameremembered"/>
        <input style="display:none" type="password" name="fakepasswordremembered"/>
        <!-- /禁止浏览器自动填充账户名密码 -->
                

    <input type="hidden" name="_form_token" value="b63232f9568b71d0ad1425ca684e67f9b546a51c877e484f987868163c47e6f2RZ11"/>
<input type="hidden" name="params" value="{&quot;server_param&quot;:&quot;c2hhcmVkX3RhaXI9dHJ1ZTtiaXpfdHlwZT1tZXJjaGFudDthY3Rpb249cGFyc2VyTG9nb25JZDs%3D&quot;,&quot;shared_tair&quot;:&quot;true&quot;}" />
<input type="hidden" name="session" value="RZ11Pu0jYCjXnsRvOUWIWJNRmBh2BamobilecashierRZ11" />

        <input type="hidden" name="check_pay_pwd" value="true" />
        <div class="am-list">
            <div class="J-inputClear am-list-item am-list-item-form am-flexbox">
                <label for="logon_id">账户 </label>
                <div class="am-flexbox-item">
                    <input id="logon_id" name="logon_id" type="text" maxlength="100" placeholder="支付宝账户" value="" autocomplete="off" autofocus="autofocus" />
                </div>
            </div>

            


    <div class="J-inputClear am-list-item am-list-item-form am-flexbox">
        <label for="pwd">密码 </label>
        <div class="am-flexbox-item">
                            <input type="password" class="J-pwd" id="pwd_unencrypt" name="pwd_unencrypt" maxlength="100" placeholder="是支付密码,不是登录密码" autocomplete="off" />
                <input type="hidden" id="pwd" name="pwd" class="J-encryptpwd" />
                    </div>
    </div>



                                </div>
        <div class="am-section">
            <div class="am-ft-pb-10">
                <button type="submit" class="am-button am-button-blue" seed="v5_need_login_new-submit">下一步</button>
            </div>
            <h5 class="am-ft-gray am-ft-mb-20">
                
                                    <a class="fn-right" href="https://d.alipay.com/i/index.htm?pageSkin=skin-h5cashier&amp;iframeSrc=alipays%3A%2F%2Fplatformapi%2FstartApp%3FappId%3D20000013%26pwdType%3DordinaryPassword" seed="v5_need_login_new-forget-pwd">忘记密码</a>
                            </h5>
        </div>
    </form>
</div>
<script type="text/javascript">
    seajs.use(['$', 'wapcashier', 'validator', 'widget', 'base', 'class', 'events'],function($, wapcashier, Validator){

        //刷新图片校验码
        var checkCode = $('.J-check-code');
        checkCode.on('click',function(e){
            var el = $(e.target);
            el.attr('src', el.attr('src') + '&s=' + Math.random())
        });

        //表单校验
        var validator = new Validator({
            element: $('form#cashier'),
            autoSubmit: false,
            stopOnError: true,
            autoFocus: false,
            onFormValidated: function(err, results, form) {
                if(!err) {
                    form[0].submit();
                } else {
                    Zepto.each(results, function(key, value){
                        if(value[1] != null) return errorMessages = value[1];
                    })
                    showMsg(errorMessages);
                }
            },
            triggerType: 'submit',
            failSilently: true
        });

        validator.addItem({
            element: '#logon_id',
            required: true,
            errormessageRequired: '支付宝账户不能为空',
            display: '支付宝账户',
            onItemValidated: function(error, message, elem) {
                if(error) window.Tracker&&Tracker.click('v5_need_login_new-' + elem.attr('name') + '-' + error);
            }
        });

                

    var isInputEvent = "oninput" in document ? true : false;
    var inputEvent = isInputEvent ? "input" : 'keyup';

    //RSA
    try {
        var dbits;var canary=0xdeadbeefcafe;var j_lm=((canary&0xffffff)==0xefcafe);function BigInteger(a,b,c){if(a!=null)
        if("number"==typeof a)this.fromNumber(a,b,c);else if(b==null&&"string"!=typeof a)this.fromString(a,256);else this.fromString(a,b);}
        function nbi(){return new BigInteger(null);}
        function am1(i,x,w,j,c,n){while(--n>=0){var v=x*this[i++]+w[j]+c;c=Math.floor(v/0x4000000);w[j++]=v&0x3ffffff;}
        return c;}
        function am2(i,x,w,j,c,n){var xl=x&0x7fff,xh=x>>15;while(--n>=0){var l=this[i]&0x7fff;var h=this[i++]>>15;var m=xh*l+h*xl;l=xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);c=(l>>>30)+(m>>>15)+xh*h+(c>>>30);w[j++]=l&0x3fffffff;}
        return c;}
        function am3(i,x,w,j,c,n){var xl=x&0x3fff,xh=x>>14;while(--n>=0){var l=this[i]&0x3fff;var h=this[i++]>>14;var m=xh*l+h*xl;l=xl*l+((m&0x3fff)<<14)+w[j]+c;c=(l>>28)+(m>>14)+xh*h;w[j++]=l&0xfffffff;}
        return c;}
        if(j_lm&&(navigator.appName=="Microsoft Internet Explorer")){BigInteger.prototype.am=am2;dbits=30;}
        else if(j_lm&&(navigator.appName!="Netscape")){BigInteger.prototype.am=am1;dbits=26;}
        else{BigInteger.prototype.am=am3;dbits=28;}
        BigInteger.prototype.DB=dbits;BigInteger.prototype.DM=((1<<dbits)-1);BigInteger.prototype.DV=(1<<dbits);var BI_FP=52;BigInteger.prototype.FV=Math.pow(2,BI_FP);BigInteger.prototype.F1=BI_FP-dbits;BigInteger.prototype.F2=2*dbits-BI_FP;var BI_RM="0123456789abcdefghijklmnopqrstuvwxyz";var BI_RC=new Array();var rr,vv;rr="0".charCodeAt(0);for(vv=0;vv<=9;++vv)BI_RC[rr++]=vv;rr="a".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;rr="A".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;function int2char(n){return BI_RM.charAt(n);}
        function intAt(s,i){var c=BI_RC[s.charCodeAt(i)];return(c==null)?-1:c;}
        function bnpCopyTo(r){for(var i=this.t-1;i>=0;--i)r[i]=this[i];r.t=this.t;r.s=this.s;}
        function bnpFromInt(x){this.t=1;this.s=(x<0)?-1:0;if(x>0)this[0]=x;else if(x<-1)this[0]=x+this.DV;else this.t=0;}
        function nbv(i){var r=nbi();r.fromInt(i);return r;}
        function bnpFromString(s,b){var k;if(b==16)k=4;else if(b==8)k=3;else if(b==256)k=8;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else{this.fromRadix(s,b);return;}
        this.t=0;this.s=0;var i=s.length,mi=false,sh=0;while(--i>=0){var x=(k==8)?s[i]&0xff:intAt(s,i);if(x<0){if(s.charAt(i)=="-")mi=true;continue;}
        mi=false;if(sh==0)
        this[this.t++]=x;else if(sh+k>this.DB){this[this.t-1]|=(x&((1<<(this.DB-sh))-1))<<sh;this[this.t++]=(x>>(this.DB-sh));}
        else
        this[this.t-1]|=x<<sh;sh+=k;if(sh>=this.DB)sh-=this.DB;}
        if(k==8&&(s[0]&0x80)!=0){this.s=-1;if(sh>0)this[this.t-1]|=((1<<(this.DB-sh))-1)<<sh;}
        this.clamp();if(mi)BigInteger.ZERO.subTo(this,this);}
        function bnpClamp(){var c=this.s&this.DM;while(this.t>0&&this[this.t-1]==c)--this.t;}
        function bnToString(b){if(this.s<0)return"-"+this.negate().toString(b);var k;if(b==16)k=4;else if(b==8)k=3;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else return this.toRadix(b);var km=(1<<k)-1,d,m=false,r="",i=this.t;var p=this.DB-(i*this.DB)%k;if(i-->0){if(p<this.DB&&(d=this[i]>>p)>0){m=true;r=int2char(d);}
        while(i>=0){if(p<k){d=(this[i]&((1<<p)-1))<<(k-p);d|=this[--i]>>(p+=this.DB-k);}
        else{d=(this[i]>>(p-=k))&km;if(p<=0){p+=this.DB;--i;}}
        if(d>0)m=true;if(m)r+=int2char(d);}}
        return m?r:"0";}
        function bnNegate(){var r=nbi();BigInteger.ZERO.subTo(this,r);return r;}
        function bnAbs(){return(this.s<0)?this.negate():this;}
        function bnCompareTo(a){var r=this.s-a.s;if(r!=0)return r;var i=this.t;r=i-a.t;if(r!=0)return(this.s<0)?-r:r;while(--i>=0)if((r=this[i]-a[i])!=0)return r;return 0;}
        function nbits(x){var r=1,t;if((t=x>>>16)!=0){x=t;r+=16;}
        if((t=x>>8)!=0){x=t;r+=8;}
        if((t=x>>4)!=0){x=t;r+=4;}
        if((t=x>>2)!=0){x=t;r+=2;}
        if((t=x>>1)!=0){x=t;r+=1;}
        return r;}
        function bnBitLength(){if(this.t<=0)return 0;return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));}
        function bnpDLShiftTo(n,r){var i;for(i=this.t-1;i>=0;--i)r[i+n]=this[i];for(i=n-1;i>=0;--i)r[i]=0;r.t=this.t+n;r.s=this.s;}
        function bnpDRShiftTo(n,r){for(var i=n;i<this.t;++i)r[i-n]=this[i];r.t=Math.max(this.t-n,0);r.s=this.s;}
        function bnpLShiftTo(n,r){var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<cbs)-1;var ds=Math.floor(n/this.DB),c=(this.s<<bs)&this.DM,i;for(i=this.t-1;i>=0;--i){r[i+ds+1]=(this[i]>>cbs)|c;c=(this[i]&bm)<<bs;}
        for(i=ds-1;i>=0;--i)r[i]=0;r[ds]=c;r.t=this.t+ds+1;r.s=this.s;r.clamp();}
        function bnpRShiftTo(n,r){r.s=this.s;var ds=Math.floor(n/this.DB);if(ds>=this.t){r.t=0;return;}
        var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<bs)-1;r[0]=this[ds]>>bs;for(var i=ds+1;i<this.t;++i){r[i-ds-1]|=(this[i]&bm)<<cbs;r[i-ds]=this[i]>>bs;}
        if(bs>0)r[this.t-ds-1]|=(this.s&bm)<<cbs;r.t=this.t-ds;r.clamp();}
        function bnpSubTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]-a[i];r[i++]=c&this.DM;c>>=this.DB;}
        if(a.t<this.t){c-=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB;}
        c+=this.s;}
        else{c+=this.s;while(i<a.t){c-=a[i];r[i++]=c&this.DM;c>>=this.DB;}
        c-=a.s;}
        r.s=(c<0)?-1:0;if(c<-1)r[i++]=this.DV+c;else if(c>0)r[i++]=c;r.t=i;r.clamp();}
        function bnpMultiplyTo(a,r){var x=this.abs(),y=a.abs();var i=x.t;r.t=i+y.t;while(--i>=0)r[i]=0;for(i=0;i<y.t;++i)r[i+x.t]=x.am(0,y[i],r,i,0,x.t);r.s=0;r.clamp();if(this.s!=a.s)BigInteger.ZERO.subTo(r,r);}
        function bnpSquareTo(r){var x=this.abs();var i=r.t=2*x.t;while(--i>=0)r[i]=0;for(i=0;i<x.t-1;++i){var c=x.am(i,x[i],r,2*i,0,1);if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1))>=x.DV){r[i+x.t]-=x.DV;r[i+x.t+1]=1;}}
        if(r.t>0)r[r.t-1]+=x.am(i,x[i],r,2*i,0,1);r.s=0;r.clamp();}
        function bnpDivRemTo(m,q,r){var pm=m.abs();if(pm.t<=0)return;var pt=this.abs();if(pt.t<pm.t){if(q!=null)q.fromInt(0);if(r!=null)this.copyTo(r);return;}
        if(r==null)r=nbi();var y=nbi(),ts=this.s,ms=m.s;var nsh=this.DB-nbits(pm[pm.t-1]);if(nsh>0){pm.lShiftTo(nsh,y);pt.lShiftTo(nsh,r);}
        else{pm.copyTo(y);pt.copyTo(r);}
        var ys=y.t;var y0=y[ys-1];if(y0==0)return;var yt=y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);var d1=this.FV/yt,d2=(1<<this.F1)/yt,e=1<<this.F2;var i=r.t,j=i-ys,t=(q==null)?nbi():q;y.dlShiftTo(j,t);if(r.compareTo(t)>=0){r[r.t++]=1;r.subTo(t,r);}
        BigInteger.ONE.dlShiftTo(ys,t);t.subTo(y,y);while(y.t<ys)y[y.t++]=0;while(--j>=0){var qd=(r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);if((r[i]+=y.am(0,qd,r,j,0,ys))<qd){y.dlShiftTo(j,t);r.subTo(t,r);while(r[i]<--qd)r.subTo(t,r);}}
        if(q!=null){r.drShiftTo(ys,q);if(ts!=ms)BigInteger.ZERO.subTo(q,q);}
        r.t=ys;r.clamp();if(nsh>0)r.rShiftTo(nsh,r);if(ts<0)BigInteger.ZERO.subTo(r,r);}
        function bnMod(a){var r=nbi();this.abs().divRemTo(a,null,r);if(this.s<0&&r.compareTo(BigInteger.ZERO)>0)a.subTo(r,r);return r;}
        function Classic(m){this.m=m;}
        function cConvert(x){if(x.s<0||x.compareTo(this.m)>=0)return x.mod(this.m);else return x;}
        function cRevert(x){return x;}
        function cReduce(x){x.divRemTo(this.m,null,x);}
        function cMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r);}
        function cSqrTo(x,r){x.squareTo(r);this.reduce(r);}
        Classic.prototype.convert=cConvert;Classic.prototype.revert=cRevert;Classic.prototype.reduce=cReduce;Classic.prototype.mulTo=cMulTo;Classic.prototype.sqrTo=cSqrTo;function bnpInvDigit(){if(this.t<1)return 0;var x=this[0];if((x&1)==0)return 0;var y=x&3;y=(y*(2-(x&0xf)*y))&0xf;y=(y*(2-(x&0xff)*y))&0xff;y=(y*(2-(((x&0xffff)*y)&0xffff)))&0xffff;y=(y*(2-x*y%this.DV))%this.DV;return(y>0)?this.DV-y:-y;}
        function Montgomery(m){this.m=m;this.mp=m.invDigit();this.mpl=this.mp&0x7fff;this.mph=this.mp>>15;this.um=(1<<(m.DB-15))-1;this.mt2=2*m.t;}
        function montConvert(x){var r=nbi();x.abs().dlShiftTo(this.m.t,r);r.divRemTo(this.m,null,r);if(x.s<0&&r.compareTo(BigInteger.ZERO)>0)this.m.subTo(r,r);return r;}
        function montRevert(x){var r=nbi();x.copyTo(r);this.reduce(r);return r;}
        function montReduce(x){while(x.t<=this.mt2)
        x[x.t++]=0;for(var i=0;i<this.m.t;++i){var j=x[i]&0x7fff;var u0=(j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;j=i+this.m.t;x[j]+=this.m.am(0,u0,x,i,0,this.m.t);while(x[j]>=x.DV){x[j]-=x.DV;x[++j]++;}}
        x.clamp();x.drShiftTo(this.m.t,x);if(x.compareTo(this.m)>=0)x.subTo(this.m,x);}
        function montSqrTo(x,r){x.squareTo(r);this.reduce(r);}
        function montMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r);}
        Montgomery.prototype.convert=montConvert;Montgomery.prototype.revert=montRevert;Montgomery.prototype.reduce=montReduce;Montgomery.prototype.mulTo=montMulTo;Montgomery.prototype.sqrTo=montSqrTo;function bnpIsEven(){return((this.t>0)?(this[0]&1):this.s)==0;}
        function bnpExp(e,z){if(e>0xffffffff||e<1)return BigInteger.ONE;var r=nbi(),r2=nbi(),g=z.convert(this),i=nbits(e)-1;g.copyTo(r);while(--i>=0){z.sqrTo(r,r2);if((e&(1<<i))>0)z.mulTo(r2,g,r);else{var t=r;r=r2;r2=t;}}
        return z.revert(r);}
        function bnModPowInt(e,m){var z;if(e<256||m.isEven())z=new Classic(m);else z=new Montgomery(m);return this.exp(e,z);}
        BigInteger.prototype.copyTo=bnpCopyTo;BigInteger.prototype.fromInt=bnpFromInt;BigInteger.prototype.fromString=bnpFromString;BigInteger.prototype.clamp=bnpClamp;BigInteger.prototype.dlShiftTo=bnpDLShiftTo;BigInteger.prototype.drShiftTo=bnpDRShiftTo;BigInteger.prototype.lShiftTo=bnpLShiftTo;BigInteger.prototype.rShiftTo=bnpRShiftTo;BigInteger.prototype.subTo=bnpSubTo;BigInteger.prototype.multiplyTo=bnpMultiplyTo;BigInteger.prototype.squareTo=bnpSquareTo;BigInteger.prototype.divRemTo=bnpDivRemTo;BigInteger.prototype.invDigit=bnpInvDigit;BigInteger.prototype.isEven=bnpIsEven;BigInteger.prototype.exp=bnpExp;BigInteger.prototype.toString=bnToString;BigInteger.prototype.negate=bnNegate;BigInteger.prototype.abs=bnAbs;BigInteger.prototype.compareTo=bnCompareTo;BigInteger.prototype.bitLength=bnBitLength;BigInteger.prototype.mod=bnMod;BigInteger.prototype.modPowInt=bnModPowInt;BigInteger.ZERO=nbv(0);BigInteger.ONE=nbv(1);function Arcfour(){this.i=0;this.j=0;this.S=new Array();}
        function ARC4init(key){var i,j,t;for(i=0;i<256;++i)
        this.S[i]=i;j=0;for(i=0;i<256;++i){j=(j+this.S[i]+key[i%key.length])&255;t=this.S[i];this.S[i]=this.S[j];this.S[j]=t;}
        this.i=0;this.j=0;}
        function ARC4next(){var t;this.i=(this.i+1)&255;this.j=(this.j+this.S[this.i])&255;t=this.S[this.i];this.S[this.i]=this.S[this.j];this.S[this.j]=t;return this.S[(t+this.S[this.i])&255];}
        Arcfour.prototype.init=ARC4init;Arcfour.prototype.next=ARC4next;function prng_newstate(){return new Arcfour();}
        var rng_psize=256;var rng_state;var rng_pool;var rng_pptr;function rng_seed_int(x){rng_pool[rng_pptr++]^=x&255;rng_pool[rng_pptr++]^=(x>>8)&255;rng_pool[rng_pptr++]^=(x>>16)&255;rng_pool[rng_pptr++]^=(x>>24)&255;if(rng_pptr>=rng_psize)rng_pptr-=rng_psize;}
        function rng_seed_time(){rng_seed_int(new Date().getTime());}
        if(rng_pool==null){rng_pool=new Array();rng_pptr=0;var t;if(window.crypto&&window.crypto.getRandomValues){var ua=new Uint8Array(32);window.crypto.getRandomValues(ua);for(t=0;t<32;++t)
        rng_pool[rng_pptr++]=ua[t];}
        if(navigator.appName=="Netscape"&&navigator.appVersion<"5"&&window.crypto){var z=window.crypto.random(32);for(t=0;t<z.length;++t)
        rng_pool[rng_pptr++]=z.charCodeAt(t)&255;}
        while(rng_pptr<rng_psize){t=Math.floor(65536*Math.random());rng_pool[rng_pptr++]=t>>>8;rng_pool[rng_pptr++]=t&255;}
        rng_pptr=0;rng_seed_time();}
        function rng_get_byte(){if(rng_state==null){rng_seed_time();rng_state=prng_newstate();rng_state.init(rng_pool);for(rng_pptr=0;rng_pptr<rng_pool.length;++rng_pptr)
        rng_pool[rng_pptr]=0;rng_pptr=0;}
        return rng_state.next();}
        function rng_get_bytes(ba){var i;for(i=0;i<ba.length;++i)ba[i]=rng_get_byte();}
        function SecureRandom(){}
        SecureRandom.prototype.nextBytes=rng_get_bytes;function parseBigInt(str,r){return new BigInteger(str,r);}
        function linebrk(s,n){var ret="";var i=0;while(i+n<s.length){ret+=s.substring(i,i+n)+"\n";i+=n;}
        return ret+s.substring(i,s.length);}
        function byte2Hex(b){if(b<0x10)
        return"0"+b.toString(16);else
        return b.toString(16);}
        function pkcs1pad2(s,n){if(n<s.length+11){alert("Message too long for RSA");return null;}
        var ba=new Array();var i=s.length-1;while(i>=0&&n>0){var c=s.charCodeAt(i--);if(c<128){ba[--n]=c;}
        else if((c>127)&&(c<2048)){ba[--n]=(c&63)|128;ba[--n]=(c>>6)|192;}
        else{ba[--n]=(c&63)|128;ba[--n]=((c>>6)&63)|128;ba[--n]=(c>>12)|224;}}
        ba[--n]=0;var rng=new SecureRandom();var x=new Array();while(n>2){x[0]=0;while(x[0]==0)rng.nextBytes(x);ba[--n]=x[0];}
        ba[--n]=2;ba[--n]=0;return new BigInteger(ba);}
        function RSAKey(){this.n=null;this.e=0;this.d=null;this.p=null;this.q=null;this.dmp1=null;this.dmq1=null;this.coeff=null;}
        function RSASetPublic(N,E){if(N!=null&&E!=null&&N.length>0&&E.length>0){this.n=parseBigInt(N,16);this.e=parseInt(E,16);}
        else
        alert("Invalid RSA public key");}
        function RSADoPublic(x){return x.modPowInt(this.e,this.n);}
        function RSAEncrypt(text){var m=pkcs1pad2(text,(this.n.bitLength()+7)>>3);if(m==null)return null;var c=this.doPublic(m);if(c==null)return null;var h=c.toString(16);if((h.length&1)==0)return h;else return"0"+h;}
        RSAKey.prototype.doPublic=RSADoPublic;RSAKey.prototype.setPublic=RSASetPublic;RSAKey.prototype.encrypt=RSAEncrypt;var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var b64padchar="=";function hex2b64(h){var i;var c;var ret="";for(i=0;i+3<=h.length;i+=3){c=parseInt(h.substring(i,i+3),16);ret+=b64map.charAt(c>>6)+b64map.charAt(c&63);}
        if(i+1==h.length){c=parseInt(h.substring(i,i+1),16);ret+=b64map.charAt(c<<2);}
        else if(i+2==h.length){c=parseInt(h.substring(i,i+2),16);ret+=b64map.charAt(c>>2)+b64map.charAt((c&3)<<4);}
        while((ret.length&3)>0)ret+=b64padchar;return ret;}

        var rsa_n = 'B98DC71833036E62C92BF6ABA5DFDDABBD44E52932CAE2026ED2A71C22E7681644A3233276F2EB7B29EC56CB720A3B8A8BFAEEA3E5E00D03E4E82203F676EBF5';
        var rsa_e = '10001';
        var encrypt = function(data) {
            var setRSA = new RSAKey();
            setRSA.setPublic(rsa_n, rsa_e);
            var res = setRSA.encrypt(data);
            if(res) {
                return linebrk(hex2b64(res), 64);
            } else {
                return '*';
            }
        }
        var pwd = $('.J-pwd');
        var encryptpwd = $('.J-encryptpwd');
        var isPaste = false;
        var clean = function () {
            pwd.val('');
            encryptpwd.val('');
        }
        clean();
        var setRange = function (el) {
            el.setSelectionRange(parseInt(el.value.length + 1), parseInt(el.value.length + 1))
        }

        pwd.on('focus',function(e){
            var el = e.target;
            setRange(el);
        });
        pwd.on('keydown',function(e){
            var el = e.target;
            if (e.which === 8 || e.which === 46) clean();
            setRange(el);
        });
        pwd.on('keyup',function(e){
            var el = e.target;
            setRange(el);
        });
        pwd.on('paste',function(e){
            isPaste = true;
        });
        //默认清空加密(浏览器点返回会保留之前的值)
        encryptpwd.val('');
        pwd.on(inputEvent,function(e){
            var el = e.target;
            if (isPaste)  clean();
            isPaste = false;
            setRange(el);
            var currentPW =  el.value.split('*').slice(-1).toString();
            var encryptPW =  encryptpwd[0].value;
            //删除(触发input事件,未获取删除keycode)
            if(currentPW.length === 0) {
                encryptpwd[0].value = encryptpwd[0].value.split(',').slice(0, el.value.length).toString();
            } else {
                //新增
                for (var i=0;i < currentPW.length;i++) {
                    var outkey = encrypt(currentPW[i]);
                    if(encryptpwd.val() === ''){
                        encryptpwd.val(outkey);
                    } else {
                        encryptpwd[0].value += ',' + outkey;
                    }
                }
                el.value = el.value.replace(/\S/g,"*")
            }
        });
    }catch(e){}
validator.addItem({
    element: '#pwd',
    required: true,
    errormessageRequired: '请填写支付密码',
    display: '支付密码',
    onItemValidate: function(error, message, elem) {
        if($('.J-encryptpwd').val() === '') {
            $('.J-encryptpwd').val($('.J-pwd').val());
        }
    },
    onItemValidated: function(error, message, elem) {
        if($('.J-encryptpwd').val() === '') {
            $('.J-encryptpwd').val($('.J-pwd').val());
        }
        if(error) {
            $('.J-pwd').val('');
            $('.J-encryptpwd').val('');
        }
        if(error) window.Tracker&&Tracker.click('v5_need_login_new-' + elem.attr('name') + '-' + error);
    }
});
                
    });
        
$(function(){
        
    
            $('.J-back').on('click',function(e){
            window.history.back();
            e.preventDefault();
        });
    
        $('.J-loading').addClass('fn-hide');

                
        
        $('.J-open-protocol').on('click',function(e){
        var el = $(this);
        Zepto.dialog.show({
            message: '<div style="height: 280px;-webkit-overflow-scrolling:touch;overflow:auto;"><iframe style="height: 280px;width: 100%;overflow: auto;" src="' + el.attr('href') + '" frameborder="0" scrolling="auto" allowTransparency="true"></iframe></div>',
            buttons: '确定',
            complete: function () {
                Zepto.dialog.hide();
            }
        });
        e.preventDefault();
    });

    // fix dialog连续闪动的问题
    Zepto.dialog.hide = function() {
        $('body').find('.am-dialog-mask').remove();
        $('body').find('.am-dialog-box').remove();
    }
});
</script>

    <script type="text/javascript">
        var form_tk = "b63232f9568b71d0ad1425ca684e67f9b546a51c877e484f987868163c47e6f2RZ11";
        var json_ua;
    </script>
    <script src="https://rds.alipay.com/ua_mobilecashier_login.js?t=2017081515"></script>

<script>
    (function (w, d, t) {
        var s = d.createElement(t), m = d.getElementsByTagName(t)[0];
        s.async = 1;
        s.src = "https://g.alicdn.com/sd/pointman/js/pt2.js?f=m&_=" + Math.floor((new Date()).getTime() / 36e5);
        m.parentNode.insertBefore(s, m);

        w._pointman_q = w._pointman_q || [];
        _pointman_q.push(["um", function (um) {
            um.init({
                timeout: 3000,
                token:'P14c3df62cee8d4bb94634ae243d1ad82',
                userid: '',
                serviceLocation: "cn",
                appName: 'mobileclientgw'
            });
        }]);
    })(window, document, "script");
</script>

<footer>
    <div class="alipay-logo"></div>
    <div id="ServerNum">mobileclientgw-30-5</div>
</footer>
<!-- CMS:安全支付客户端网关/common/footer.vm开始:mobileclientgw/common/footer.vm -->    <script type="text/javascript">
if(navigator.userAgent.indexOf('sdk') > 0) {$('input[data-format]').attr('data-format', '100')}
//12.03下线
if(window.Zepto && Zepto.dialog && $('.J-header-return') != -1){
  Zepto.dialog.hide = function() {
      $('body').find('.am-dialog-mask').animate({
          opacity: 0
      }, 400, 'ease-out', function(){
          $(this).css('display', 'none');
      });
      $('body').find('.am-dialog-box').animate({
          opacity: 0
      }, 400, 'ease-out', function(){
          $(this).css('display', 'none');
      });
      window.setTimeout(function(){
          $('body').find('.am-dialog-mask').remove();
          $('body').find('.am-dialog-box').remove();
      },1000);
  }
}
</script><!-- CMS:安全支付客户端网关/common/footer.vm结束:mobileclientgw/common/footer.vm --></body>
</html>

改造后

改造到最后呢,页面逻辑清爽多了,再有新的模块,写好之后别人直接调用就可以了,write once, run everywhere .

define(function(require) {

    var $ = require("jquery"),
        $body = $(document.body),
        setDate = require("components/setDate"),
        selectCity = require("components/selectCity"),
        commonTools = require("tools/commonTools"),
        FastClick = require("fastClick"),
        myLayer = require("myLayer");


    //内部统计
    var webTrends = require("webTrends");
    webTrends.init();

    // 百度统计
    var baiduTrends = require("baiduTrends");
    baiduTrends.init();

    // 初始化时间选择
    setDate.dateTime.init();
    
    //  选择目的地
    selectCity.init();

    var actionList = {

      'applyInsurance' :function(){
          //xxx
      }
  });    

完整的代码就不展示了,都是一些逻辑,没什么好看的。

最后

花了大概一个周的时间初步重构了一下项目代码,改得很粗糙,只是做了一些大概的拆分,毕竟遗留的代码太多,需要和小伙伴一起做这个事。

由于公司标装的电脑用不了npm那些,最后的一步是我在mac上弄好,然后拷贝到公司电脑上,中间还出了很多问题,不过好在能跑了,至于最后能不能用起来..只能说,努力吧。

seajs 可以说是上个年代的产物了,不过在一些老旧项目中,依然可以发挥光和热。

写到这里差不多也要结束了,我呢,也算完成了给自己定的一个小目标,不算多大的贡献,只当给自己一个交代。

以上大概就是全部内容,希望给大家带来一些启发和帮助,谢谢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
模块化是一种将程序中的代码按照一定的规则拆分成独立的模块,使得代码的维护和复用更加方便的技术。在 JavaScript 中,有三种常见的模块化规范:CommonJS、AMD(Asynchronous Module Definition)和CMD(Common Module Definition)。 CommonJS 是 Node.js 默认的模块化规范,它主要用于服务器端的 JavaScript 开发。它定义了一个 require 函数来加载模块,一个 exports 对象来导出接口,并支持模块的循环依赖。CommonJS 规范的代码示例: ```javascript // 导出模块 exports.add = function (num1, num2) { return num1 + num2; } // 加载模块 var math = require('math'); console.log(math.add(2, 3)); ``` AMD 是一种异步加载模块的规范,主要用于浏览器端的 JavaScript 开发。它需要使用一个专门的模块加载器来异步加载模块,比如 requirejs。 ```javascript // 定义模块 define(['jquery'], function ($) { function add(num1, num2) { return num1 + num2; } return { add: add } }); // 加载模块 require(['math'], function (math) { console.log(math.add(2, 3)); }); ``` CMD 是另一种异步加载模块的规范,与 AMD 类似,也需要使用一个专门的模块加载器来异步加载模块,比如 sea.js。 ```javascript // 定义模块 define(function (require, exports, module) { var $ = require('jquery'); function add(num1, num2) { return num1 + num2; } exports.add = add; }); // 加载模块 seajs.use('math', function (math) { console.log(math.add(2, 3)); }); ``` 总的来说,CommonJS 主要用于服务器端的 JavaScript 开发,AMD 和 CMD 主要用于浏览器端的 JavaScript 开发,它们都帮助我们更好地组织和复用代码。同时,由于 ECMAScript 6 以后原生支持模块化,使用 import 和 export 关键字即可实现模块化编程,更加简洁方便。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值