这不是一篇介绍seajs和backbone的文章,如果对这两个库不太了解,可以去他们官网查阅。欢迎转载,注明出处:http://www.cnblogs.com/mapping/archive/2013/03/03/2941812.html
单页面应用(spa:single page application)的业务逻辑多是比较复杂的,如果一次性把整个spa用到的文件加出估计得卡到不行,使用seajs可以很好的实现按需加载;使用backbone可以比较方便地实现数据、逻辑、表现分离,有人称他为前端的MVC框架,又有人说他不算是MVC,这里就不做讨论。
本文主要讲解如何使用这两个库实现spa里模块根据路由的自动加载
首先建立整个app的文件结构,如图:
根目录:autoload;
根目录下index.html作为app首页及入口,js目录放置app的js文件;
js目录中base放置基本的依赖js库,main目录放置app的框架代码,module目录就是用来放置各个模块的功能js啦;
下一步就是把underscore、jquery、backbone源码包装成CMD规范(或参考这里)的文件,underscore和backbone已内置AMD接口,jquery最新版也已添加AMD的exports接口,如果是旧版的jquery需要return $.noConfilt(true),如下:
base/jquery.js
define('base/jquery', function(require) { //jquery官方源码 return $.noConflict(true); });
base/underscore.js
define('base/underscore', function(require, exports, module) { //underscore官方源码 });
base/backbone.js
define('base/backbone', ['underscore', '$'], function(require, exports, module) { this._ = require('underscore'); this.jQuery = require('$'); //backbone官方源码 });
用过backbone的人都知道,使用他的路由功能来做spa非常方便,页面较少的情况还可以,如果页面一多,每次都要改路由配置;虽然backbone也支持多个Router对象,但每次新增模块还是避免不了增加对应的router规则,就需要维护多个文件;而且配置的router越多,出现重复的概率就会越大,所以我们就要制定一个统一的router规则来实现模块自动加载,其实就是把模块的功能文件路径及文件名作为参数传给router处理函数,然后使用seajs的require.async方法去加载对应的文件,如下:
main/app.js
define('main/app', function(require, exports) { var Backbone = require('backbone'); //配置路由 var autoRouter = Backbone.Router.extend({ routes: { '': 'home', 'at/:module/:action(/*condition)': 'loadmodule' }, home: function() { this.loadmodule('home', 'index'); }, //按照at/module/action(/conditions)格式的請求自動加載模塊 loadmodule: function(md, ac, con) { //将参数字符串'a:123/b:456'转换为json对象{a:123, b:456} var cj = {}; if(con && con.indexOf(':') > -1) { con.replace(/(\w+)\s*:\s*([\w-]+)/g, function(a, b, c) { b && (cj[b] = c); }); } else { cj = con; } //加载module目录下对应的模块 require.async(['module', md, ac].join('/'), function(cb) { if(cb) { cb(cj); } else { alert('模塊加載失敗!'); } }) } }); //定义全局变量App window.App = { Models: {}, Views: {}, Collections: {}, initialize: function() { new autoRouter(); Backbone.history.start(); } }; exports.run = App.initialize; })
这里给路由一个非常yy的名称at(把模块@出来^_^),任何匹配'at/:module/:action(/*condition)'规则的路径都会调用loadmodule方法,在这里condition是一个可选参数,如果要传递多个参数可以写成‘a:123/b:456’的格式,loadmodule方法会将这个格式字符串转换成json方便模块里的代码调用
autoRouter对象中还有一个空路由用于app的启动,实际这条路由相当于'at/home/index';我们现在要做的就是在module目录里加模块文件了:
module/home/index.js
define('module/home/index', ['backbone'], function(reuqire) { var Backbone = reuqire('backbone'); App.Models.Home = Backbone.Model.extend({}); App.Collections.Home = Backbone.Collection.extend({ model: App.Models.Home }); App.Views.Home = Backbone.View.extend({ el: '#container', initialize: function(c) { this.Collections = c; this.render(); }, render: function() { var html = ''; this.Collections.each(function(m) { html += '<div><a href="' + m.get('link') + '">' + m.get('name') + '</a></div>'; }); this.$el.html(html); } }) return function() { //模拟数据 var hc = new App.Collections.Home(); hc.add([ {'name': '加载模块A', 'link': '#at/m/a/name:moduleA/other:nothing'}, {'name': '加载模块B', 'link': '#at/m/b'} ]); new App.Views.Home(hc); } });
注意:每个自动加载的模块都必须返回一个function,用于loadmodule方法callback,否则,提示模块加载失败;
这个function一般都用来将加出来的模块初始化,如上面的index.js,这里会在页面添加两个链接用来加载模块A和模块B,再看下页面index.html的代码:
index.html
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>seajs+backbone实现单页面模块自动加载</title> </head> <body> <div id="container"> </div> <script type="text/javascript" src="js/base/sea.js"></script> <script type="text/javascript"> seajs.config({ base: '/js/', alias: { //基础库 'underscore': 'base/underscore', '$': 'base/jquery', 'backbone': 'base/backbone', 'app': 'main/app' } }); seajs.use('app', function(app) { app.run(); }); </script> </body> </html>
到这里,整个app已经可以运行啦
但是点击“加载模块A”或“加载模块B”都会弹出模块加载失败,那是因为我们还没添加这两个模块
module/m/a.js
define('module/m/a', ['$'], function(reuqire) { var $ = reuqire('$'); return function(c) { alert('moduleA加载成功,参数:' + $.param(c)); } });
加载模块A运行结果:
module/m/b.js
define('module/m/b', ['$'], function(reuqire) { return function(c) { alert('moduleB加载成功,参数:' + c); } });
加载模块B运行结果:
好了,我们整个demo已经结束了,本文只是简单介绍一种模块自动加载的思路。
如果是做一个完整的spa,那么还有模块依赖的样式css文件、模板html文件需要加载以及从api拉取数据,这些功能借助seajs和backbone都可以比较方便实现,加载模板html文件你或许需要seajs的plugin-text.js插件
本文demo打包下载:autoload.zip
欢迎转载,注明出处:http://www.cnblogs.com/mapping/archive/2013/03/03/2941812.html