场景用页面的切换都是在每个场景动作结束后自动切换到另一个场景。一般来说在代码设计上尽量不要让不相关的代码耦合,所以场景之间尽量不要直接调用另外一个场景代码。常规的来说,一般抽出到更上层通信了,提供一个统一的接口让应用的不同部分进行通信
这里具体看下右边代码区域christmas.js中的代码
页面类pageA、pageB、pageC都提供一个完成的回调函数,常规来说,因为有依赖所以就会有回调嵌套的问题。对了,可能想起来另一个解决方法 Deferred了,运用的思路其实差不多,但是这里更为直接的我引入了Observer模式
new pageA(function() { new pageB(function() { new pageC(function() { //执行下一个 }) }) })
给每个场景对象订阅一个"完成"的事件,然后在每个场景运行结束发派发这个"完成事件"
订阅场景pageA完成事件
observer.subscribe("completeA", function() { //做一些是 })
触发场景pageA完成事件
new pageA(function() { observer.publish("completeA"); //触发 })
这里其实是一对一的关系,效果还不是很明显,如果是对一多的关系,比如场景完成后,我们可以注册很多的事件
总的来说,观察者模式所做的工作就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化。
christmas.js中,通过观察者模式的处理,切面的切换都是通过事件通知。
请参考页面A切换到页面B的代码,触发B页面的代码
然后在代码56行处填写页面B切换到页面C的代码,然后触发pageC页面
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>圣诞主题</title> <link rel='stylesheet' href='common.css' /> <script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script> <script src="observer.js"></script> <script src="pageC.js"></script> <script src="pageB.js"></script> <script src="pageA.js"></script> <script src="christmas.js"></script> </head> <body> <section class="container"> <!-- 第一幅画面 --> <section class="page-a bg-adaptive"> </section> <!-- 第二幅画面 --> <section class="page-b bg-adaptive"> </section> <!-- 第三幅画面 --> <section class="page-c bg-adaptive"> </section> </section> <button>点击运行场景切换</button> <script type="text/javascript"> /** * 自适应页面大小 * @param {[type]} doc [description] * @param {[type]} win [description] * @return {[type]} [description] */ var docEl = document.documentElement, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', recalc = function() { //自适应设置容器高度 var container = document.querySelector(".container") //原始比例 var proportion = 900 / 1440; container.style.height = container.clientWidth * proportion + "px"; }; window.addEventListener(resizeEvt, recalc, false); document.addEventListener('DOMContentLoaded', recalc, false); </script> </body> </html>
/** * 慕课网特制 * 圣诞主题效果 * @type {Object} */ /** * 切换页面 * 模拟镜头效果 * @return {[type]} [description] */ function changePage(element, effect, callback) { element .addClass(effect) .one("animationend webkitAnimationEnd", function() { callback && callback(); }) } /** * 中间调用 */ var Christmas = function() { //页面容器元素 var $pageA = $(".page-a"); var $pageB = $(".page-b"); var $pageC = $(".page-c"); //观察者 var observer = new Observer(); //A场景页面 new pageA(function() { observer.publish("completeA"); }) //进入B场景 observer.subscribe("pageB", function() { new pageB(function() { observer.publish("completeB"); }) }) //进入C场景 observer.subscribe("pageC", function() { new pageC() }) //页面A-B场景切换 observer.subscribe("completeA", function() { changePage($pageA, "effect-out", function() { observer.publish("pageB"); }) }) //页面B-C场景切换 //? }; $(function() { $("button").click(function(){ //圣诞主题效果,开始 Christmas() }) })
/** * 事件 * 观察者模式 */ var Observer = (function(slice) { function bind(event, fn) { var events = this.events = this.events || {}, parts = event.split(/\s+/), i = 0, num = parts.length, part; if (events[event] && events[event].length) return this; for (; i < num; i++) { events[(part = parts[i])] = events[part] || []; events[part].push(fn); } return this; } function one(event, fn) { this.bind(event, function fnc() { fn.apply(this, slice.call(arguments)); this.unbind(event, fnc); }); return this; } function unbind(event, fn) { var events = this.events, eventName, i, parts, num; if (!events) return; parts = event.split(/\s+/); for (i = 0, num = parts.length; i < num; i++) { if ((eventName = parts[i]) in events !== false) { events[eventName].splice(events[eventName].indexOf(fn), 1); if (!events[eventName].length) { //修正没有事件直接删除空数组 delete events[eventName]; } } } return this; } function trigger(event) { var events = this.events, i, args, falg; if (!events || event in events === false) return; args = slice.call(arguments, 1); for (i = events[event].length - 1; i >= 0; i--) { falg = events[event][i].apply(this, args); } return falg; //修正带返回 } return function() { this.on = this.subscribe = bind; this.off = this.unsubscribe = unbind; this.trigger = this.publish = trigger; this.one = one; return this; }; })([].slice);
function pageA(callback) { //模拟执行时间 setTimeout(function() { callback() }, 2000) }
function pageB (callback) { //模拟执行时间 setTimeout(function() { callback() }, 1000) }
function pageC(callback) { }
*{ margin: 0; padding: 0; } /*body{ width: 100%; height: 100%; }*/ .container { width: 100%; height: 100%; position: relative; overflow: hidden; } .bg-adaptive { background-size: 100% 100%; } .container .page-a { width : 100%; height : 100%; background-image: url("http://img1.sycdn.imooc.com//565d07770001790814410901.png"); position: absolute; z-index: 5; } .container .page-b { width : 100%; height : 100%; background-image: url("http://img1.sycdn.imooc.com//565d09fa000145a614410901.png"); position: absolute; z-index: 4; } .page-c { width : 100%; height : 100%; background-image: url("http://img1.sycdn.imooc.com//565d0b280001788014410901.png"); position: absolute; z-index: 3; } /** * 页面切换 * 镜头方法 */ .effect-out{ -webkit-animation: effectOut 8s ease-in-out forwards; -webkit-transform-origin:71% 72%; -moz-animation: effectOut 8s ease-in-out forwards; -moz-transform-origin:71% 72%; } @-webkit-keyframes effectOut{ 0% { opacity:1; } 100% { -webkit-transform: scale(20); opacity:0; } } @-moz-keyframes effectOut{ 0% { opacity:1; } 100% { -moz-transform: scale(20); opacity:0; } } .effect-in{ z-index: 15; display: block; opacity:0; -webkit-transform: scale(8); -webkit-animation: effectIn 5s ease-in-out forwards; -webkit-transform-origin:58.5% 73.5%; -moz-transform: scale(8); -moz-animation: effectIn 5s ease-in-out forwards; -moz-transform-origin:58.5% 73.5%; } @-webkit-keyframes effectIn{ 100% { -webkit-transform: scale(1); opacity:1; } } @-moz-keyframes effectIn{ 100% { -moz-transform: scale(1); opacity:1; } }