美文网首页
双11实例

双11实例

作者: 火锅伯南克 | 来源:发表于2017-11-29 17:07 被阅读0次

    双11过去了,双12还会远吗。。

    对于双11web开发这一块有一些心得分享出来,希望能帮助到你

    首先明确需求:

    1.m站(也就是webapp,手机端网站)开发一个双11会场页(能够添加到购物车,有限时抢购功能),和一个双11预热页(纯展示的页面,没有交互)

    2.ios和android的APP要镶嵌这两个页面,也要实现交互

    对于公司唯一前端的我要面临的问题是:

    1.需求给到我第一让我犯愁的是抢购倒计时,因为要倒计时肯定要用到定时器,android的还没什么事,但是ios在页面滑动的的过程中js是阻塞的(相当于alert),那么要解决这个首要问题,就要实现手动滑动,我选择了swiper.js,好了,这个暂且解决。

    2.如果使用swiper.js就引发了另的个问题。容器和内容宽高要在实例化swiper时固定,这就要求内容的所有图片都要预先固定宽高,这个好说,跟运营、美工、ui好好商量一下就行了,不是什么大毛病。还有一个就是,M站是有头部导航和脚部菜单的,而APP有他们自己的头和脚,这就要求APP加载页面时要去掉头脚,然后再固定容器,实例化swiper,去掉就去掉,无非是判断一下设备,这个暂时解决。

    3.会场与预热页本来预定是分开写的,但是对于一个有追求的前端怎么能够容忍,决定两个页面写在一块,但是预热页面虽然简单,有一些动画。但是谁能保证产品什么时候让你在加点别的啥的,对吧。如果多了js自然也不会少了,会场页和预热页的全局变量,函数,对象混杂在一起,第一容易乱,第二性能也不好,那么我们接下来就针对这个问题展开后续。

    首先我们要知道一点,如果你经常阅读各类框架源码的话,对于自执行函数(IIFE)这个东西一定不会陌生,以jquery为例:

    (function(w){
        var obj = {
            //....等等一些其他的东西
        }
        w.$ = w.jQuery = obj;
    })(window,undefined)
    

    源码差不多就是这么个意思。
    作用:
    1.函数内部的变量外部不可访问,避免全局的污染。
    2.把window替换成w有利于压缩,其次是避免了多层作用域链的查找
    3.这个undefined之所以这么写是因为在ES5以前的版本中,undefined是一个可写的属性,举个例子。

        var undefined = true;
        console.log(undefined)//true
    

    在ES5以前版本中这么写是不会报错的,所以JQ开发人员为了避免事故发生就把undefined作为参数传入函数,就算你在全局定义了undefined = true,在函数内部undefined的值依然是undefined

    你可能要说了,你说的这些我都知道啊,但这跟你的要解决的问题有毛线关系?

    关系大了,我们可以模仿一下这种模块化的写法,把会场和和预热的js部分分割开来,他大概是这个样子的:

    //访问的地址http://接口?system=值&style=值
        //system取值为android或ios或m; style取值为0代表会场或1代表预热
        function getName(name) {
            var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
            var r = window.location.search.substr(1).match(reg);
            if(r!=null)return  unescape(r[2]); return null;
        }
    
        (function(arr,code){
            arr[code]();
            console.log('执行完成之后的操作')
        })([function(){ console.log('会场js') },function(){console.log('预热js')}],getName('style'))
    

    这样一来对应的js只会运行一次,且避免了全局的污染。
    但是这么做产生了一个问题;那就是欠缺对于js异步操作(ajax)的考虑,我们看这一段代码:

      (function(fn){
          fn(); 
          console.log('this')   
      })(function(){
          setTimeout(function(){
              console.log('time');
          },1000)           
      });
    //先打印出this,1秒后打印time
    

    我用setTimeout模拟了ajax,问题显而易见,这种方法并不能保证代码的执行顺序(对于js异步先行百度,以后我们再聊),你可能想到了使用回调函数的方法不就ok了吗,没错,我们试一下:

    (function(fn){
            fn(function(){          
                console.log('this')     
            }); 
        })(function(callback){
            setTimeout(function(){
                console.log('time');
                callback&&callback();
            },2000)
        });
    //先1秒后打印time,在打印出this
    

    这个显然解决了我们的燃眉之急,但是我们又忽略了一个问题,那就是多个异步这个方法还好使吗?代码不用写,想想就知道肯定不行,但是我们又不能保证一个模块里只有一个ajax请求,那么我们就来换个写法搞他

    (function(fn){
            fn(function(sum){
                this.sum = sum; 
                this.now = 0;
                this.count = function(){
                    this.now++;
                    if(this.now==this.sum){
                        this.callback();
                    }
                }
                this.callback = function(){
                    console.log('this')
                }
            }); 
        })(function(ObFn){
            var ob = new ObFn(3);
            setTimeout(function(){
                console.log('time1');
                ob.count();
            },2000)
            setTimeout(function(){
                console.log('time2');
                ob.count();
            },5000)
            setTimeout(function(){
                console.log('time3');
                ob.count();
            },3000)
        });
    

    这里我们把回调函数换成了一个构造函数,而回调函数被添加到了构造函数的属性里。然后在模块开头new一个实例出来,每次遇到异步请求的回调里写上ob.count(),确定回调的个数后添加在new的实例的参数里,每当请求成功都会触发一次ob.count()进行检测,当全部回调完成时触发console.log('this'),这个模式模仿的观察者模式。有兴趣的可以百度一下观察者模式。

    好了,style确定完成,接下来我们该说说console.log('this')这一部分该写些什么了,废话不多说,上代码:

    html部分
    <body>
        <button onclick="o.appCart(5)">点击</button>
    </body>
    
    js回调函数部分
    this.callback = function(){ 
             var u = getName('system');
             var f = {
                   //单独的方法写在这里
                  android:{
                       allFn:function (n) {
                             //安卓专用的方法
                        }
                   },
                   ios:{
                        allFn:function (n) {
                              //ios专用的方法
                        }
                    },
                    m:{
                        allFn:function (n){
                            //m站专用的方法
                        }
                    }
                }
                //通用的方法写在这里
                f[u].appCart = function (n) {
                     this.allFn(n);
                };
                window.o = f[u];
    }
    

    仔细看一下,是不是和我们开篇说的jq的模式有类似的地方呢。哈哈,大功告成,最后附上完整代码:

    html部分
    <body>
        <button onclick="o.appCart(5)">点击</button>
    </body>
    js部分
        function getName(name) {
            var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
            var r = window.location.search.substr(1).match(reg);
            if(r!=null)return  unescape(r[2]); return null;
        }
    
        (function(arr,code){
            arr[code](function(sum){
                this.sum = sum; 
                this.now = 0;
                this.count = function(){
                    this.now++;
                    if(this.now==this.sum){
                        this.callback();
                    }
                }
                this.callback = function(){
                    
                    var u = getName('system');
    
                    var f = {
                        //单独的方法写在这里
                        android:{
                            allFn:function (n) {
                                //安卓专用的方法
                            }
                        },
                        ios:{
                            allFn:function (n) {
                                //ios专用的方法
                            }
                        },
                        m:{
                            allFn:function (n){
                                //m站专用的方法
                            }
                        }
                    }
    
                    //通用的方法写在这里
                    f[u].appCart = function (n) {
                        this.allFn(n);
                    };
                    window.o = f[u];
                }
            }); 
        })([function(ObFn){
            var ob = new ObFn(2);
            $.ajax({
                url:'接口1',
                async: true,
                success:function(res){
                    ob.count();
                }
            })
            $.ajax({
                url:'接口2',
                async: true,
                success:function(res){
                    ob.count();
                }
            })
            
        },function(ObFn){
            var ob = new ObFn(2);
            $.ajax({
                url:'接口1',
                async: true,
                success:function(res){
                    ob.count();
                }
            })
            $.ajax({
                url:'接口2',
                async: true,
                success:function(res){
                    ob.count();
                }
            })
            
        }],getName('style'));      
    

    相关文章

      网友评论

          本文标题:双11实例

          本文链接:https://www.haomeiwen.com/subject/guhpbxtx.html