基本代码已经完成了,现在我们需要一点完善。
首先,在右上角有一个【详细规则】的字符串,我们需要给它添加事件——点击之后弹出一个遮罩层,遮罩层里面出现一个div,上面写了各种东西。这个div的最底部是一个超链接,可以接着进行跳转。点击遮罩层,除了div以外的部分,可以让遮罩层自动消失。
尽管这个只要利用jquery稍稍改进一下就可以了,但是这里我们需要用模块处理,好处就是,以后想要用遮罩的时候直接引用就好。于是,首先写一个模块:
1 window.Layer = (function(){ 2 3 var cssLoad = false; //代表css有没有被添加 4 var instance; //遮罩层 5 6 function init(layerContent){ 7 if(!cssLoad) { 8 //样式没有被添加 9 var style_str = ".layer_mask {position: fixed; right: 0; top: 0; bottom: 0; left: 0; background: rgba(0,0,0,.6); z-index: 1; height: 100%; }.layer {position: fixed; right: 0; top: 0; bottom: 0; left: 0; z-index: 99999; height: 100%; display: none; }"; 10 var style_instance = document.createElement('style'); 11 style_instance.innerHTML = style_str; 12 document.getElementsByTagName('head')[0].appendChild(style_instance); 13 cssLoad = true; 14 } 15 replace_content = '<div id="layer_mask" class="layer_mask"></div>' + layerContent; 16 if(!instance) { 17 instance = document.createElement('div'); 18 instance.setAttribute('class', 'layer'); 19 var content = replace_content; 20 document.body.appendChild(instance); 21 } 22 instance.innerHTML = replace_content; 23 bindEvent(); 24 show(); 25 return instance; 26 } 27 function bindEvent(){ 28 var dom = document.getElementById('layer_mask'); 29 dom.onclick = function(){ 30 hide(); 31 } 32 } 33 function show(){ 34 instance.style.display = 'block'; 35 } 36 function hide(){ 37 instance.style.display = 'none'; 38 } 39 return { 40 init: init 41 } 42 })()
上面就是一个遮罩层的模块了,一如既往,第一行暴露一个全局自执行函数,将模块暴露出去。
然后声明两个变量。
创建一个函数,第一个if语句中,作用是对遮罩层的css样式完成一次加载,这个加载是在cssLoad这个变量为false的时候才会进行的。当模块的html代码书写完毕之后,我们自然需要同时配上css,而且这个css最好跟着这个模块一起加载而不是在首页加载,这样可以减少一些不必要的资源的消耗。
这个if语句中,第一句创建一个style_str变量,写上遮罩层的所有css,当然,真正写的时候可以直接在首页上写好css,然后链接过去,调整。调整完毕后,将链接里的css代码全部复制过来,删除链接。
创建完了之后再创建style标签,然后将css全部输入,然后将这个节点元素全部加载到head标签里面去。最后将cssload的值更改,这样就不会重复加载了。
下面这个replace_content变量代表【替换内容】,毕竟,每个遮罩层里的内容都不一样,如果遮罩层模块里的内容都固定了,那么模块也就没有意义了,除非另创一个模块去继承。与其这么麻烦,不如直接让需要遮罩层的模块自己提供内容,这个遮罩层模块只负责显示,这样就完美了。
当然,这里能更改的只有文字内容,如果需要全部更改的话,就需要传进来至少2个变量,一个负责css代码,一个负责文字内容。有需要的可以自己去摸索一下,稍稍改改就好。
然后下面这个if语句就是添加遮罩层的代码了。判断遮罩层有没有加载,没有就创建一个遮罩层div,给它各种属性,这里是给它添加一个类属性,然后将这个div放到body下面完成加载。
之后就是将内容输入这个div中,调用bindEvent和show方法,启动事件调用和显示。
事件调用方法:简单的点击一个遮罩层就会启动隐藏函数。另,这里设置了冒泡解除,不然点击需要的内容也会触发这个事件。
这个模块就到此为止了。
接下来是修改原来的rank.js模块,因为增加了遮罩层和点击事件,所以对应的地方需要更新——
更新之后的代码是这样的——
1 window.rankModule = Object.create(baseModule); 2 //每个对象互相独立---》简称继承 3 (function(){ 4 var selfModule = { 5 el: $('#rank'), 6 name: '我是排名页', 7 listel: $(".js-ranklist"), 8 getlayer_content: function(){ 9 str = '<div class="layer_content">' + 10 ' <div class="rule_content">' + 11 ' <div class="rule_head">' + 12 ' 活动规则' + 13 ' </div>' + 14 ' <div class="rule_body">' + 15 ' 滴滴巴⼠将奔赴各城,填写您的乘车需求,参战城市排位战,城市排名靠前的城市就有可能第⼀时间坐到滴滴巴士,获取免费上下班的机会!' + 16 ' </div>' + 17 ' <div class="rule_submit">' + 18 ' 我要参战' + 19 ' </div>' + 20 ' </div>' + 21 '</div>' 22 return str; 23 }, 24 init: function(){ 25 this.getData(); 26 this.bindEvent(); 27 console.log('我在getData后面'); 28 console.log('我是重载的init方法'); 29 }, 30 enter: function(){ 31 this.el.show(); 32 $(EventCenter).trigger('returnTop'); 33 }, 34 renderContent: function(obj){ 35 str = ""; 36 var targetNum = null; 37 var count = 0; 38 for(var key in obj) { 39 if(count === 0) { 40 targetNum = obj[key]; 41 } 42 var LEFT_OFFSET_REM = 9.5; 43 var dotted_num = LEFT_OFFSET_REM/targetNum; 44 var left = dotted_num * obj[key]; 45 if(left < 3) { 46 left = 3 + left; 47 } 48 count++; 49 str += '<li>' + 50 ' <div class="left_pane inl">' + 51 ' <div class="rank_number inl">' + count + '</div>' + 52 ' <div class="rank_name inl">' + key + '</div>' + 53 ' </div>' + 54 ' <div data-left="' + left + '" class="right_pane inl">' + 55 ' <div class="bus_info">' + 56 ' ' + obj[key] + '人' + 57 ' </div>' + 58 ' </div>' + 59 ' <div class="barline"></div>' + 60 ' <div class="citybar" style="animation:runcity '+ (3 - obj[key]/targetNum ) +'s infinite linear both 1.5s;-webkit-animation:runcity '+ (3 - obj[key]/targetNum ) +'s infinite linear both 1.5s;"></div>' + 61 '</li>'; 62 } 63 this.listel.html(str); 64 setTimeout(function(){ 65 $(".right_pane").each(function(index, val){ 66 val.style.left = val.dataset.left + 'rem'; 67 }); 68 }, 1000) 69 //IScroll 就是iscroll.js暴露出的全局变量 70 }, 71 bindEvent: function(){ 72 var me = this; 73 this.el.find(".submit_button").click(function(){ 74 location.href = "#/formbus"; 75 }); 76 this.el.find(".rule_submit").click(function(){ 77 location.href = "#/formbus"; 78 }); 79 this.el.find('.rule_desc').click(function(){ 80 $(EventCenter).trigger('layer', me.getlayer_content()); 81 //Layer.init(); 82 }) 83 }, 84 getData: function(){ 85 var me = this; 86 $.ajax({ 87 url: "js/data.json", 88 type: 'get', 89 success:function(res){ 90 console.log('异步代码'); 91 if(typeof res === "string") { 92 res = JSON.parse(res) 93 }else { 94 res = res; 95 } 96 me.renderContent(res); 97 $(EventCenter).trigger('iscroll_load'); 98 console.log(res); 99 }, 100 error: function(res){ 101 console.log(res); 102 } 103 }) 104 } 105 } 106 $.extend(rankModule,selfModule); 107 })();
和原来的相比,多了getlayer_content方法,而bindEvent函数当中多了3个事件。
首先是这个getlayer_content方法。
这个就是简单的,将原本应该写在首页的代码写在了这个js文档中,并将内容转变为字符串,保存在str当中。这个函数执行后会得到这个字符串。
得到的字符串通过事件就可以传给遮罩层代码执行了。
然后是3个点击事件,其中前面两个分别是用来跳转的,通过更改哈希值,完成页面的跳转。可能会有人会误解这里解释一下,请看下面的代码:
<a href="#home">home</a>
这是一个超链接,是个页内跳转的超链接,上面看起来高大上的哈希值和跳转实质上就是指这个玩意儿,只是表现形式不同而已。如果你给这个超链接设置显示隐藏的js代码,就可以实现之前所讲的路由跳转了。当然,这个要代替那些个路由跳转代码是不可能的,就算功能一样,实现起来也有诸多的限制。
最后一个事件会触发事件中心layer函数,同时会传进去一个参数,这个参数就是后面代码的执行结果,即调用getlayer_content()后得到的str字符串。
于是这个模块也修改完毕。
回到事件中心,打开init,js,我们继续补充代码,多了个遮罩层启动用的事件。下面的vex是第三方插件,也是一个遮罩层,如果自己实在是写不好,也可以直接调用这个来用。
一般来说,这个rank基本上就算完成了。但是,这里还有几个细节和遗留问题需要处理:
首先,我们的rank页面有循环出来的数据,但是这些数据明显不能全部显示出来,多余的部分需要通过滚动条拉出来,所以我们需要一个滚动条。
当数据获取成功的时候,我们就可以设置滚动条了,于是这个代码可以写在ajax里面,成功的情况当中:
$(EventCenter).trigger('iscroll_load');
触发一个触发器。
相应的事件中心也要增加一个滚动代码:
$(EventCenter).bind('iscroll_load', function(){
var myScroll = new IScroll('.rank_list', {
scrollbars: true,
probeType: 2, //滚动条的灵敏性设置
bounce:true
});
});
然后,我们需要注意冒泡,当遮罩出来的时候,这个滚动条不能动,所以我们需要删除冒泡。
这个属于css代码,而且属于动态加载的代码,所以写在了一开始的遮罩层模块的
style_str
当中。