距離上一篇文章已經有好幾個月,也不是沒有時間記錄點東西,主要是換了新的工作,在一家外資工作,目前的工作內容大多都是前端開發,新接觸的東西因為時間原因,大多還不成體系,所以這么長時間什么都沒記錄下來,也正是因為新的工作內容,才有了今天這篇文章。
這篇文章是我自己的博客項目的前端重寫,因為目前asp.net API和單頁應用的流行,結合目前工作中用到的東西,我決定把我的博客項目的前端部分整個重寫,(以前的就是一坨…)
RequireJS http://www.requirejs.org/
Knockout http://knockoutjs.com/
BootStrap http://getbootstrap.com/
PubSubJS https://github.com/mroderick/PubSubJS
如果沒有接觸過的朋友請自行谷歌百度吧,就不浪費口水,額,鍵盤啦,什么,沒有jQuery,呵呵,呵呵,正如Knockout官方文檔里說的,Everyoue loves jquery。
RequireJS我用來做模塊加載器,Knockout做MVVM分離也是爽到沒朋友(誰用誰知道),Bootstrap搭建界面布局,PubSub,看著名字就知道啦。
Libs:放置上文中提到的各種框架和工具;
App:主要的工作目錄,articleList、catalog、articleViewer分別代表整個前端應用中的一個組件,對應的.html文件是他們自身的視圖模板;
Utilities:存放一些工具類,如檢測設備、格式化Url和字符串等;
Layout:只有一個文件,存放了整個前端應用的模板,可以通過更改這個文件,來改變各個組件的表現形式。
為這個示例,我只準備了三個服務端API:
GetCatalog 得到文章類型目錄:
namespace MiaoBlog.Controllers.API
{
public class CatalogController:ApiController
{
public IEnumerable<CategoryView> Get()
{
GetAllCategoriesResponse response = articleCatalogService.GetAllCategories();
return response.Categories;
}
}
}
GetArticlesByCategory 根據類型ID和頁面編號獲取文章目錄,
GetArticle 根據文章ID獲取文章內容等信息:
namespace MiaoBlog.Controllers.API
{
public class ArticlesController:ApiController
{
public IEnumerable<ArticleSummaryView> GetArticlesByCategory(int categoryId, int pageNumber)
{
GetArticlesByCategoryRequest request = GenerateArticlesByCategoryRequestFrom(categoryId, pageNumber-1);
GetArticlesByCategoryResponse response = articleCatalogService.GetArticlesByCategory(request);
return response.Articles;
}
public ArticleDetailPageView GetArticle(int id)
{
ArticleDetailPageView detailView = new ArticleDetailPageView();
GetArticleRequest request = new GetArticleRequest() { ArticleId = id };
GetArticleResponse response = articleCatalogService.GetArticle(request);
ArticleView articleView = response.Article;
detailView.Article = articleView;
detailView.Comments = response.Comments;
detailView.Tags = response.Tags;
return detailView;
}
PRivate static GetArticlesByCategoryRequest GenerateArticlesByCategoryRequestFrom(int categoryId, int index)
{
GetArticlesByCategoryRequest request = new GetArticlesByCategoryRequest();
request.NumberOfResultsPerPage = int.Parse(applicationSettingsFactory.GetApplicationSettings().NumberOfResultsPerPage);
request.Index = index;
request.CategoryId = categoryId;
request.ExcerptLength = int.Parse(ApplicationSettingsFactory.GetApplicationSettings().ExcerptLength);
return request;
}
}
}
這里我用到的Require的幾個常用插件:domReady、CSS、text.
paths配置了引用的js的別稱:
paths:{
'lib/jquery': './Libs/jquery-1.11.1',
'lib/underscore': './Libs/underscore',
'lib/unserscore/string': './Libs/underscore.min',
'lib/backbone':'./Libs/backbone',
'lib/backbone/eproxy':'./Libs/backbone.eproxy',
'lib/backbone/super': './Libs/backbone.super',
'lib/pubsub': './Libs/pubsub',
'r/css': './Libs/css',
'r/less': './Libs/less',
'r/text': './Libs/text',
'r/domReady': './Libs/domReady',
'r/normailize': './Libs/normalize',
'pubsub': './Libs/pubsub',
'lib/ko': './Libs/knockout-3.2.0',
'utility': './Utilities/utility',
'util/matrix2d': './Utilities/matrix2d',
'util/meld':'./Utilities/meld',
'lib/bootstrap': './Libs/bootstrap-3.2.0/dist/js/bootstrap',
'lib/bootstrap/css': './Libs/bootstrap-3.2.0/dist/css/'
},
shim的配置略過;
然后就是require的調用入口了,從這里啟動整個前端應用:
require(['lib/jquery', 'r/domReady', 'lib/underscore', 'config', 'r/text!Layout/template.html', 'r/css!lib/bootstrap/css/bootstrap.css', 'lib/bootstrap', ], function ($, domReady, _, config, template) {
domReady(function () {
var rootContainer = $("body").find("[data-container='root']");
var oTemplate=$(template);
var modules = $("[data-module]",oTemplate);
_.each(modules, function (module, index) {
require(["App/" + $(module).attr("data-module")], function (ModuleClass) {
var combineConfig = _.defaults(config[$(module).attr("data-module")], config.application);
var oModule = new ModuleClass(combineConfig);
oModule.load();
oModule.render(modules[index]);
});
});
rootContainer.append(oTemplate);
});
});
這里看到了template.html通過r/text引入,上文中提到過,它就是整個應用程序的模板文件,先看一下它的結構我再接著解釋代碼內容:
<div class="container">
<div class="row">
<div class="col-lg-3" data-module="catalog"></div>
<div class="col-lg-9" data-module="articleList"></div>
</div>
<div data-module="articleViewer"></div>
</div>
define(function () {
return {
application: {
Events: {
SWITCH_CATEGORY:"Miaoblog_Switch_Category",
OPEN_ARTICLE:"Miaoblog_Open_Article"
}
},
catalog: {
APIs: {
GetCatalog: {
Url: "http://localhost:15482/api/Catalog"
}
}
},
articleList: {
APIs: {
GetArticleList: {
Url: "http://localhost:15482/api/Articles",
ParamsFormat: "categoryId={0}&pageNumber={1}"
}
}
},
articleViewer: {
APIs: {
GetArticle: {
Url:"http://localhost:15482/api/Articles/{0}"
}
}
}
};
});
就已catalog模塊為例,先貼上代碼,再做解釋:
/// <reference path="../Libs/require.js" />
define(['lib/jquery', 'lib/ko', 'lib/underscore','pubsub', 'r/text!App/catalogList.html'],
function ($, ko,_, hub,template) {
var app = function (config) {
this.catalogList = null;
this.oTemplate = $(template);
this.config = config;
}
_.extend(app.prototype, {
load: function () {
var self = this;
$.Ajax({
type: "GET",
async: false,
url: self.config.APIs.GetCatalog.Url,
dataType: "json",
success: function (data) {
self.catalogList = data;
},
error: function (jqXHR, textStatus, error) {
console.log(error);
}
});
},
render: function (container) {
var self = this;
var oContainer = $(container);
var list = {
categories: ko.observableArray(),
switchCategory: function (selected) {
//alert("Hello world"+selected.Id);
hub.publish(self.config.Events.SWITCH_CATEGORY, selected.Id);
}
};
list.categories(self.catalogList);
oContainer.append(this.oTemplate);
ko.applyBindings(list, this.oTemplate.get(0));
}
});
return app;
});
<ul class="nav nav-pills nav-stacked" data-bind="foreach:categories">
<li>
<a href="#" data-bind="attr:{categoryId:Id},click:$parent.switchCategory">
<!--ko text: Name--><!--/ko-->
<span class="badge pull-right" data-bind="text:ArticlesCount"></span>
</a>
</li>
</ul>
上一節中提到了Pubsub發布了一個事件出去,意圖是希望文章列表或者其他什么關心這個事件的組件去做它自己的工作,在這個示例中當然就只有articleList這個組件了,來看一下這個組件的代碼:
/// <reference path="../Libs/require.js" />
define(['lib/jquery', 'lib/ko', 'lib/underscore', 'utility', 'pubsub', 'r/text!App/articleList.html','r/css!App/CommonStyle/style.css'],
function ($, ko, _, utility,hub,layout) {
var app = function (config) {
this.config = config;
this.oTemplate = $(layout);
this.currentPageArticles = null;
this.currentCategoryId = null;
this.currentPageNumber = null;
this.articleListViewModel = null;
}
_.extend(app.prototype, {
initialize:function(){
},
load: function () {
var self = this;
hub.subscribe(this.config.Events.SWITCH_CATEGORY, function (msg, data) {
self.switchCategory(data);
});
},
render: function (container) {
var self = this;
var oContainer = $(container);
this.articleListViewModel = {
articles: ko.observableArray(),
openArticle: function (selected) {
hub.publish(self.config.Events.OPEN_ARTICLE, selected.Id);
}
};
oContainer.append(this.oTemplate);
ko.applyBindings(this.articleListViewModel, this.oTemplate.get(0));
},
switchCategory: function (categoryId) {
var self = this;
self.currentCategoryId = categoryId;
self.currentPageNumber = 1;
$.ajax({
type: "GET",
async: true,
url: utility.FormatUrl(false,self.config.APIs.GetArticleList,categoryId,self.currentPageNumber),
dataType: "json",
success: function (data) {
self.articleListViewModel.articles(data);
}
});
},
turnPage: function (pageNumber) {
}
});
return app;
}
);
onedrive就不用了,雖然很搞到上,但是誰知道哪天就又…你懂的
百度網盤地址:http://pan.baidu.com/s/1o6meoKa
新聞熱點
疑難解答