1. 程式人生 > >Emberjs之模組化路由,讓一切按需載入。

Emberjs之模組化路由,讓一切按需載入。

Emberjs的模組化很弱, 需要在html頁面中加入所有模板,引入所有的控制器,檢視。使這個html檔案很大,程式碼很多。

可能大家都想過要把模板放到外面獨立的檔案中,我也如此,所以實現了一個模組化的Ember路由,來實現此功能。

核心程式碼如下:

/*
	動態載入路由所需的模版以及元件
*/
(function() {
	Ember.USE_MODULE_ROUTE = true;
	var get = Ember.get,
		set = Ember.set,
		forEach = Ember.EnumerableUtils.forEach;

	var setupPromises = [];
	var setupFuns = [];
	//由於現在新的setup是非同步的,而Ember.Route的setup必須按順序執行,
	//所以此處維護一個佇列來確保Ember.Route的setup方法順序執行.

	function _runSetupQueue() {
		Ember.RSVP.all(setupPromises).then(function() {
			forEach(setupFuns, function(funObj) {
				var route = funObj.context;
				if(!route._abortRender){
					funObj.fn.apply(route, funObj.args);
				}
			});
			setupPromises.length = 0;
			setupFuns.length = 0;
		});
	}

	/**
		擴充套件Ember.Route
		{@link http://emberjs.com/guides/routing/defining-your-routes/|詳見原始文件}.
		@class Ember.Route
	*/
	Ember.Route.reopen({
		/**
			模版載入器的模組名
			@memberof Ember.Route
			@default "text"
			@instance
		*/
		templateLoader: "text",
		/**
			模版檔案的目錄
			@memberof Ember.Route
			@default "./templates/"
			@instance
		*/
		templateDir: "./templates/",
		/**
			該路由需要從templateDir目錄下請求的模版名陣列,如果只有一個,可以是字串.
			如不指定該屬性, 只會將與路由名對應的模板加入請求列表.
			如果指定了該屬性, 則只會請求該屬性指定的模版.
			所以,可以將該屬性設定為空陣列[], 則不會請求任何模版.
			@memberof Ember.Route
			@default null
			@instance
		*/
		templateNames: null,
		/**
			該路由需要用到的元件類.
			@memberof Ember.Route
			@default null
			@instance
		*/
		dependences: null,
		exit: function() {
			this._abortSetup = true;
			this._super();
		},
		setup: function(context) {
			this._abortSetup = false;
			var setupPromise = this._setup();
			setupPromises.push(setupPromise);
			setupFuns.push({
				fn: this.__nextSuper,
				args: [context],
				context: this
			});
			Ember.run.once(null, _runSetupQueue);
		},
		_setup: function() {
			var route = this;
			return new Ember.RSVP.Promise(function(resolve, reject) {
				var routeName,
					TEMPLATES,
					templateLoader,
					templateDir,
					tplNames,
					dependences,
					depsTplNames,
					depsTplUrls;

				if (route.constructor != "Ember.Route") {
					routeName = route.routeName.replace(/\./g, '/');
				}

				TEMPLATES = Ember.TEMPLATES;
				templateLoader = route.templateLoader;
				templateDir = route.templateDir;

				tplNames = route.templateNames;
				if(Ember.USE_MODULE_ROUTE){
					tplNames = tplNames || routeName || [];
				} else {
					tplNames = tplNames || [];
				}
				tplNames = typeof tplNames == "string" ? [tplNames] : [].concat(tplNames);

				dependences = route.dependences || [];
				dependences = typeof dependences == "string" ? [dependences] : [].concat(dependences);
				depsTplNames = [];
				depsTplUrls = [];

				forEach(tplNames, function(tplName, i, self) {
					if (!TEMPLATES.hasOwnProperty(tplName)) {
						depsTplNames.push(tplName);
						depsTplUrls.push(templateLoader + "!" + templateDir +
							tplName + ".hbs");
					}
				});

				dependences = [].concat(depsTplUrls, dependences);

				if(dependences.length == 0){
					Ember.run(null, resolve);
				}else{
					require(dependences, function() {
						var modules = arguments;
						forEach(depsTplNames, function(tplName, i) {
							TEMPLATES[tplName] = Ember.Handlebars.compile(modules[i]);
						});
						Ember.run(null, resolve);
					});
				}

			});
		}
	});
})();