玩過knockoutjs的都知道,有一個強大的功能叫做component,而這個component有個牛逼的地方就是擁有自己的viewmodel和template,
比如下面這樣:
ko.components.register('message-editor', { viewModel: function(){}, template:"" });
很顯然,viewmodel就是function函式區,而template就是模板區,然後通過register函式將component註冊到knockout中,下面我們演示一個簡單
的功能,就是動態的顯示當前“input”內容的length長度。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <meta charset="utf-8" /> <script src="jquery-1.8.2.js"></script> <script src="knockoutjs.js"></script> </head> <body> <div data-bind='component: "message-editor"'></div> <script type="text/javascript"> ko.components.register('message-editor', { viewModel: function (params) { this.text = ko.observable(params && params.initialText || ''); }, template: 'Message: <input data-bind="value: text" /> ' + '(length: <span data-bind="text: text().length"></span>)' }); ko.applyBindings(); </script> </body> </html>
請仔細看一下這段程式碼,當前的component會將template模板inject到html的div的標籤中,而且這個template標記中還有一個text元素的繫結,
而這個(text().length)的資料來源剛好就是viewModel中的this.text..對吧。。。有了這兩個的合一,我們最後的html展示如下:
接下來我們隨便輸入一些數字,移開滑鼠,這個時候會觸發input的change事件,比如下面這樣。
是不是好吊??? 當然有些人可能要問,如果在input呈現的時候賦予一點預設值呢???可不可以呢?當然也是可以的,這個時候我們可以在
data-bind中預設賦予值就ok啦。。。比如下面這樣:
1 <body> 2 <h4>Second instance, passing parameters</h4> 3 <div data-bind='component: { name: "message-editor", params: { initialText: "Hello, world!" }}'></div> 4 5 <script type="text/javascript"> 6 7 ko.components.register('message-editor', { 8 viewModel: function (params) { 9 this.text = ko.observable(params && params.initialText || ''); 10 }, 11 template: 'Message: <input data-bind="value: text" /> ' 12 + '(length: <span data-bind="text: text().length"></span>)' 13 }); 14 15 ko.applyBindings(); 16 </script> 17 </body>
可以看到,上面的程式碼中我通過在component中的params物件中加入一個initialText屬性,這個時候就可以將這個initialText動態的注入到
我們的viewModel中,然後我們的input和span元素通過data-bind 訂閱了這個viewModel中的this.text監控屬性,這個時候就出現了實時更新操
作了,迫不及待的看一下吧~
一:問題分析
好了,通過上面的演示,你或許發現到瞭如下兩個問題,第一個問題就是好強大,只要你register就可以了,根本不需要通過applyBindings來
施加一個viewmodel,這樣就實現了頁面的模組化,真的好便捷~ 所以這個問題是一個好事情, 第二個問題就是我們的template模板中的內容是
通過“硬編碼“的形式,也就是如果這個內容有很多,比如有100行,200行,那我們是不是瘋了??? 就是你能耐再大也沒法一一拼接起來,就算
拼起來,維護成本也太大了,所以問題來了,如何將template的content動態化??? 比如現實中我們看到的 百度文庫 的頁面。。。如下圖:
這個頁面中,有很多的模組,比如我圈出來的上面3個,這三個模組中的html肯定還是很多的吧~~~
二:template動態獲取
html內容的動態獲取,通常有兩種方式,第一種就是RequireJs,當然你需要引用這麼一個js,第二種就是我們重寫他們的模板,當然這篇我
們講解後面的這種方式,我們要做的就是重寫component中的loadTemplate函式,然後替換預設的defaultLoader載入器,是不是很簡單呢???
1. 重寫loadtemplate方法
//第一步:重寫loadTemplate方法 var templateFromUrlLoader = { loadTemplate: function(name, templateConfig, callback) { if (templateConfig.fromUrl) { var fullUrl = '/' + templateConfig.fromUrl //ajax動態獲取外部的file內容 $.get(fullUrl, function(markupString) { ko.components.defaultLoader.loadTemplate(name, markupString, callback); }); } else { callback(null); } } }; //替換原來的defaultLoader,實現新的templateFromUrlLoader ko.components.loaders.unshift(templateFromUrlLoader);
2. 將hard codeing 放入到外部的file,比如我新建了一個file.html檔案。
3. 再register元件,然後在template標記上引用外面檔案路徑,比如下面的{ fromUrl: 'file.html' }
ko.components.register('message-editor', { viewModel: function (params) { this.text = ko.observable(params && params.initialText || ''); }, template: { fromUrl: 'file.html' }, });
好了,所有功能都準備完畢了,我們瀏覽一下頁面,看看是啥樣的???
終於大功搞成了,對不對撒~~~然後是不是就可以延伸到上面介紹的“百度文庫”的例子,我們可以把各個模組的html放到一個單獨的檔案中,
對吧,好了,本篇就說到這裡,希望對你有幫助~~~
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <meta charset="utf-8" /> <script src="jquery-1.8.2.js"></script> <script src="knockoutjs.js"></script> </head> <body> <div data-bind='component: { name: "message-editor", params: { initialText: "你好撒!!!" }}'></div> <script type="text/javascript"> //第一步:重寫loadTemplate方法 var templateFromUrlLoader = { loadTemplate: function (name, templateConfig, callback) { if (templateConfig.fromUrl) { var fullUrl = '/' + templateConfig.fromUrl //ajax動態獲取外部的file內容 $.get(fullUrl, function (markupString) { ko.components.defaultLoader.loadTemplate(name, markupString, callback); }); } else { callback(null); } } }; //替換原來的defaultLoader,實現新的templateFromUrlLoader ko.components.loaders.unshift(templateFromUrlLoader); ko.components.register('message-editor', { viewModel: function (params) { this.text = ko.observable(params && params.initialText || ''); }, template: { fromUrl: 'file.html' }, }); ko.applyBindings(); </script> </body> </html>