Blog | Phodal - A Growth Engineerhttp://www.phodal.com/blog/2016-11-28T01:08:44.642805+00:00BlogBackbone router 正则表达式2014-11-12T14:29:32+00:002015-04-08T06:22:16.762728+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-backbone-router-regex-replace-default-method/在使用Backbone的过程中,发现原来还可以在Backbone Router中使用正则表达式。
##Backbone Router
> Backbone.Router担任了一部分Controller(控制器)的工作,它一般运行在单页应用中,能将特定的URL或锚点规则绑定到一个指定的方法。
在一开始使用Backbone Router的时候,用的是类似于下面的方法来寝化一个Router
Backbone.Router.extend({
routes: {
"users": "showUsers"
},
showUsers: function() {
UserController.showUsers();
}
});
var UserController = {
showUsers: function() {
var usersView = new UsersView();
usersView.render();
$("#user_list").html(usersView.el);
}
}
而实际上Backbone Router是可以支持regex的
##Backbone Router 正则表达式
官网中给了一个简单的示例
initialize: function(options) {
this.route("page/:number", "page", function(number){ ... });
this.route(/^(.*?)\/open$/, "open");
},
open: function(id) { ... }
于是接着就对自己的Router进行了一次重构,之前的Router大致如下所示
define([
'jquery',
'underscore',
'backbone',
'js/HomeView.js',
'js/CreateAccountView.js'
],function($, _, Backbone, HomeView, CreateAccountView){
var AppRouter = Backbone.Router.extend({
routes: {
'index': 'homePage',
'account/create': 'Create'
}
});
window.app = new AppRouter();
var initialize = function() {
var router = new AppRouter;
router.on('route:homePage', function() {
new HomeView();
});
router.on('route:Create', function() {
var createAccountView = new CreateAccountView();
createAccountView.render();
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
修改完后的router如下所示:
define([
'jquery',
'underscore',
'backbone',
'js/HomeView.js',
'js/CreateAccountView.js'
],function($, _, Backbone, HomeView, CreateAccountView){
var AppRouter = Backbone.Router.extend({
index: function(){
var homeView = new HomeView();
homeView.initialize();
},
createAccount: function(){
var createAccountView = new CreateAccountView();
createAccountView.render();
},
initialize: function() {
var router = this,
routes = [
[ /^.*$/, "index" ],
[ ":account/create", "createAccount" ]
];
_.each(routes, function(route) {
router.route.apply(router,route);
});
Backbone.history.stop();
Backbone.history.start();
}
});
window.app = new AppRouter();
return AppRouter;
});
构建基于Javascript的移动CMS——添加滑动2014-07-28T18:56:37+00:002014-07-30T01:10:28.494612+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-add-swipe/
在和几个有兴趣做**移动CMS**的小伙伴讨论了一番之后,我们觉得当前比较重要的便是统一一下RESTful API。然而最近持续断网中,又遭遇了一次停电,暂停了对API的思考。在周末无聊的时光了看了《人间失格》,又看了会《一个人流浪,不必去远方》。开始思考所谓的技术以外的事情,或许这将是下一篇讨论的话题。
正在我对这个[移动CMS](http://cms.moqi.mobi/)的功能一筹莫展的时候,帮小伙伴在做一个图片滑动的时候,便想着将这个功能加进去,很顺利地找到了一个库。
##移动CMS滑动
我们所需要的两个功能很简单
- 当用户向右滑动的时候,菜单应该展开
- 当用户向左滑动的时候,菜单应该关闭
在官网看到了一个简单的示例,然而并不是用于这个菜单,等到我完成之后我才知道:为什么不用于菜单?
找到了这样一个符合功能的库,虽然知道要写这个功能也不难。相比于自己写这个库,还不如用别人维护了一些时候的库来得简单、稳定。
> jQuery Plugin to obtain touch gestures from iPhone, iPod Touch and iPad, should also work with Android mobile phones (not tested yet!)
然而,它并不会其他一些设备上工作。
###添加jQuery Touchwipe
添加到requirejs的配置中:
require.config({
baseUrl: 'lib/',
paths: {
jquery: 'jquery-2.1.1.min',
router: '../router',
touchwipe: 'jquery.touchwipe.min'
},
shim: {
touchwipe: ["jquery"],
underscore: {
exports: '_'
}
}
});
require(['../app'], function(App){
App.initialize();
});
(注:上面的代码中暂时去掉了一部分无关本文的,为了简单描述。)
接着,添加下面的代码添加到app.js的初始化方法中
$(window).touchwipe({
wipeLeft: function() {
$.sidr('close');
},
wipeRight: function() {
$.sidr('open');
},
preventDefaultEvents: false
});
就变成了我们需要的代码。。
define([
'jquery',
'underscore',
'backbone',
'router',
'jquerySidr',
'touchwipe'
], function($, _, Backbone, Router){
var initialize = function(){
$(window).touchwipe({
wipeLeft: function() {
$.sidr('close');
},
wipeRight: function() {
$.sidr('open');
},
preventDefaultEvents: false
});
$(document).ready(function() {
$('#sidr').show();
$('#menu').sidr();
$("#sidr li a" ).bind('touchstart click', function() {
if(null != Backbone.history.fragment){
_.each($("#sidr li"),function(li){
$(li).removeClass()
});
$('a[href$="#/'+Backbone.history.fragment+'"]').parent().addClass("active");
$.sidr('close');
window.scrollTo(0,0);
}
});
});
Router.initialize();
};
return {
initialize: initialize
};
});
便可以实现我们需要的
- 当用户向右滑动的时候,菜单应该展开
- 当用户向左滑动的时候,菜单应该关闭
##其他
然而在Windows Phone的IE浏览器中,左滑动和右滑动分别是前进和后退。
CMS效果: [墨颀 CMS](http://cms.moqi.mobi/)
QQ讨论群: 344271543
项目: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi) 构建基于Javascript的移动CMS——生成博客(三).重构2014-07-25T13:55:55+00:002014-07-25T14:23:54.877377+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-blog-refactor/当前[墨颀CMS](http://cms.moqi.mobi/)的一些基础功能设计已经接近尾声了,在完成博客的前两部分之后,我们需要对此进行一个简单的重构。为的是提取出其中的获取Blog内容的逻辑,于是经过一番努力之后,终于有了点小成果。
##墨颀CMS 重构
我们想要的结果,便是可以直接初始化及渲染,即如下的结果:
initialize: function(){
this.getBlog();
},
render: function(response){
var about = {
about:aboutCMS,
aboutcompany:urlConfig["aboutcompany"]
};
response.push(about);
this.$el.html(Mustache.to_html(blogPostsTemplate, response));
}
为的便是简化其中的逻辑,将与View无关的部分提取出来,最后的结果便是都放在初始化里,显然我们需要一个``render``,只是暂时放在``initialize``应该就够了。下面便是最后的结果:
initialize: function(){
var params='#content';
var about = {
about:aboutCMS,
aboutcompany:configure["aboutcompany"]
};
var blogView = new RenderBlog(params, '/1.json', blogPostsTemplate);
blogView.renderBlog(about);
}
我们只需要将id、url、template传进去,便可以返回结果,再用getBlog部分传进参数。再渲染结果,这样我们就可以提取出两个不同View里面的相同的部分。
##构建函数
于是,我们就需要构建一个函数RenderBlog,只需要将id,url,template等传进去就可以了。
var RenderBlog = function (params, url, template) {
this.params = params;
this.url = url;
this.template = template;
};
用Javascript的原型继承就可以实现这样的功能,虽然还不是很熟练,但是还是勉强用了上来。
RenderBlog.prototype.renderBlog = function(addInfo) {
var template = this.template;
var params = this.params;
var url = this.url;
var collection = new BlogPostModel;
collection.initialize(url);
collection.fetch({
success: function(collection, response){
if(addInfo !== undefined){
response.push(addInfo);
}
RenderBlog.prototype.render(params, template, response);
}
});
};
RenderBlog.prototype.render = function(params, template, response) {
$(params).html(Mustache.to_html(template, response));
};
大致便是将原来的函数中的功能抽取出来,再调用自己的方法。于是就这样可以继续进行下一步了,只是暂时没有一个明确的方向。
###其他
CMS效果: [墨颀 CMS](http://cms.moqi.mobi/)
QQ讨论群: 344271543
项目: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi)
构建基于Javascript的移动CMS——生成博客(一)2014-07-23T14:37:31+00:002014-07-24T07:12:07.196795+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-a-simple-blog/在[墨颀 CMS](http://cms.moqi.mobi)中的动态的文章是从我博客的API加载过来的,因为当前没有其他好的CMS当接口。之前直接拿博客的DB文件+Nodejs+RESTify生成了一个博客的API,而且可以支持跨域请求。
##简单的博客构成
这次我们可以简单的做一个可以供移动平台阅读的博客,除了不能写作以外(ps:不能写作还能叫博客么)。对于写博客的人来说更多的只是写,而对于读者来说,他们只需要读,所以在某种意义上可以将博客的写和读分离开来。
对于用户来说,博客是由两个页面构建的:
- 博文列表(blogposts list)
- 博客内容(blogposts detail)
在这里我们先关注博文列表
###博文列表
博文列表的内容一般有:
- 作者(Author)
- 标题(title)
- 创建时间/修改时间(Time)
- 关键词(Keywords)
- 摘要(Description)
- 链接(Slug)
一个简单的示例如下,也就是我们接下来要用到的**1.json**中的一部分。
[{
"title": "构建基于Javascript的移动web CMS入门——简介",
"slug": "use-jquery-backbone-mustache-build-mobile-app-cms",
"description": "看到项目上的移动框架,网上寻找了一下,发现原来这些一开始都有。于是,找了个示例开始构建一个移动平台的CMS——墨颀 CMS,方便项目深入理解的同时,也可以自己维护一个CMS系统。",
"keywords": [
"backbone",
"jquery",
"underscore",
"mustache"
],
"created": "2014-07-17 14:16:18.035763"
}]
这里基本上也就有了上面的要素,除了作者,当然因为作者只有一个,所以在里面写作者就是在浪费流量和钱啊。接着我们就是要把上面的内容读取出来放到CMS里。和之前不同的是,虽然我们可以用和[墨颀CMS文件 JSON文件](http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-json-configure/)一样的方法,但是显然这种方法很快就会不适用。
##移动CMS 获取在线数据
这里会用到Backbone的Model,我们先创建一个Model
var BlogPostModel = Backbone.Model.extend({
name: 'Blog Posts',
url: function(){
return this.instanceUrl;
},
initialize: function(props){
this.instanceUrl = props;
}
});
我们需要在初始化的时候传入一个URL,以便在``getBlog``的时候用到,为了方便调试将url改为同路径的1.json文件
getBlog: function() {
var url = '/1.json';
var that = this;
collection = new BlogPostModel;
collection.initialize(url);
collection.fetch({
success: function(collection, response){
that.render(response);
}
});
},
这样当成功获取数据的时候便render页面。最后的HomeView.js代码如下所示:
define([
'jquery',
'underscore',
'mustache',
'text!/index.html',
'text!/blog.html'
], function($, _, Mustache, indexTemplate, blogTemplate) {
var BlogPostModel = Backbone.Model.extend({
name: 'Blog Posts',
url: function(){
return this.instanceUrl;
},
initialize: function(props){
this.instanceUrl = props;
}
});
var HomeView = Backbone.View.extend({
el: $('#aboutArea'),
initialize: function(){
this.getBlog();
},
getBlog: function() {
var url = '/1.json';
var that = this;
collection = new BlogPostModel;
collection.initialize(url);
collection.fetch({
success: function(collection, response){
that.render(response);
}
});
},
render: function(response) {
this.$el.html(Mustache.to_html(blogTemplate, response));
}
});
return HomeView;
});
这样也就意味着我们需要在index.html中创建一个id为aboutArea的div。接着我们需要创建一个新的Template——blog.html,它的内容就比较简单了,只是简单的Mustache的使用。
{{#.}}
<h2><a alt="{{title}}" href="http://www.phodal.com/blog/tag/underscore/feeds/atom/%7B%7Bslug%7D%7D">{{title}}</a>
<p>{{description}}</p>
{{/.}}
``{{#.}}``及``{{/.}}``可以用于JSON数组,即循环,也可以是判断是否存在。
最后的结果便是:
<h2><a alt="构建基于Javascript的移动web CMS入门——简介" href="http://www.phodal.com/blog/tag/underscore/feeds/atom/use-jquery-backbone-mustache-build-mobile-app-cms">构建基于Javascript的移动web CMS入门——简介</a></h2>
<p>看到项目上的移动框架,网上寻找了一下,发现原来这些一开始都有。于是,找了个示例开始构建一个移动平台的CMS——墨颀 CMS,方便项目深入理解的同时,也可以自己维护一个CMS系统。</p>
把description去掉,再修改一个CSS,便是我们在首页看到的结果。
下一次我们将打开这些URL。
###其他
####如何查看是否支持JSON跨域请求
本次代码下载:[https://github.com/gmszone/moqi.mobi/archive/0.1.1.zip](https://github.com/gmszone/moqi.mobi/archive/0.1.1.zip)
一个简单的工具就是
curl I -s http://example.com
在这里我们查看
curl -I -s http://api.phodal.net/blog/page/1
应该要返回 Access-Control-Allow-Origin: *
HTTP/1.1 200 OK
Server: mokcy/0.17.0
Date: Thu, 24 Jul 2014 00:38:19 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 3943
Connection: keep-alive
Vary: Accept-Encoding
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-Requested-With
Cache-Control: max-age=600
CMS效果: [墨颀 CMS](http://cms.moqi.mobi/)
QQ讨论群: 344271543
项目: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi) </h2>构建基于Javascript的移动web CMS——加载JSON文件2014-07-22T15:01:30+00:002014-07-23T00:03:52.234881+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-json-configure/在上一篇中说到了如何创建一个[Django Tastypie API](http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-work-with-django/)给[移动CMS](http://cms.moqi.mobi)用,接着我们似乎也应该有一个本地的配置文件用于一些简单的配置,如"获取API的URL"、"产品列表"、"SEO"(在一开始的时候发现这是不好的,后面又发现Google的爬虫可以运行Javascript,不过也是不推荐的。)这些东西是不太需要修改的,直接写在代码中似乎又不好,于是放到了一个叫作``configure.json``的文件里。
##RequireJS Plugins
网上搜索到一个叫RequireJS Plugins的repo。
里面有这样的几个插件:
- **async** : Useful for JSONP and asynchronous dependencies (e.g. Google Maps).
- **font** : Load web fonts using the [WebFont Loader API](https://code.google.com/apis/webfonts/docs/webfont_loader.html)
(requires `propertyParser`)
- **goog** : Load [Google APIs](http://code.google.com/apis/loader/)
asynchronously (requires `async!` plugin and `propertyParser`).
- **image** : Load image files as dependencies. Option to "cache bust".
- **json** : Load JSON files and parses the result. (Requires `text!` plugin).
- **mdown** : Load Markdown files and parses into HTML. (Requires `text!`
plugin and a markdown converter).
- **noext** : Load scripts without appending ".js" extension, useful for
dynamic scripts.
于是,我们可以用到这里的json用来加载JSON文件,虽然也可以用Requirejs的text插件,但是这里的json有对此稍稍的优化。
在后面的部分中我们也用到了mdown,用于显示一个md文件,用法上大致是一样的。
##RequireJS JSON文件加载
将json.js插件放到目录里,再配置好main.js。
require.config({
paths: {
'text': 'text',
jquery: 'jquery',
json: 'require/json'
},
shim: {
underscore: {
exports: '_'
}
}
});
require(['app'], function(App) {
App.initialize();
});
于是我们将HomeView.js中的data变为configure的数据,这样便可以直接使用这个json文件。
define([
'jquery',
'underscore',
'mustache',
'text!/index.html',
'json!/configure.json'
], function($, _, Mustache, indexTemplate, configure) {
var HomeView = Backbone.View.extend({
el: $('#aboutArea'),
render: function() {
this.$el.html(Mustache.to_html(indexTemplate, configure));
}
});
return HomeView;
});
configure.json的代码如下所示:
{
"project": "My Sample Project"
}
最后实现的效果和模板结束是一样的,只会在页面上显示
My Sample Project
##结束
###获取代码
一、使用git
git clone https://github.com/gmszone/moqi.mobi
git co b03f54c
二、直接下载
###其它
CMS效果: [墨颀 CMS](http://cms.moqi.mobi/)
QQ讨论群: 344271543
项目: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi)构建基于Javascript的移动web CMS——整合Django2014-07-21T12:52:49+00:002014-07-21T13:35:05.363629+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-work-with-django/正在一步步完善[墨颀 CMS](http://cms.moqi.mobi/),在暂时不考虑其他新的功能的时候,先和[自己的博客](http://www.phodal.com)整合一下。
##Django Tastypie 跨域
###Django Tastypie示例
之前用AngluarJS做的全部文章的时候是Tastypie做的API,只是用来生成的是博客的内容。只是打开的速度好快,可以在1秒内打开,献上URL:
[http://www.phodal.com/api/v1/url/?offset=0&limit=20&format=json](http://www.phodal.com/api/v1/url/?offset=0&limit=20&format=json)
之前只是拿Tastypie生成一些简单的JSON数据,如keywords_string,slug,title这些简单的数据。
因为这里的Blogpost是来自mezzanine,原来的``api.py``,如下所示:
from tastypie.resources import ModelResource
from mezzanine.blog.models import BlogPost, BlogCategory
class AllBlogSlugResource(ModelResource):
class Meta:
queryset = BlogPost.objects.published()
resource_name = "url"
fields = ['keywords_string', 'slug', 'title']
allowed_methods = ['get']
class BlogResource(ModelResource):
class Meta:
queryset = BlogPost.objects.published()
resource_name = "blog"
fields = ['keywords_string', 'slug', 'title', 'content', 'description']
allowed_methods = ['get']
而这时为了测试方便,还需要解决跨域请求的问题,生成的内容大致如下所示:
{
"meta": {
"limit": 1,
"next": "/api/v1/url/?offset=1&limit=1&format=json",
"offset": 0,
"previous": null,
"total_count": 290
},
"objects": [
{
"keywords_string": "jquery backbone mustache underscore siderbar",
"resource_uri": "/api/v1/url/369/",
"slug": "use-jquery-backbone-mustache-build-mobile-app-cms-add-jquery-plugins",
"title": "构建基于Javascript的移动web CMS——添加jQuery插件"
}
]
}
###Django Tastypie 跨域支持
于是网上搜索了一下,有了下面的代码:
from tastypie.resources import Resource, ModelResource
from mezzanine.blog.models import BlogPost, BlogCategory
from django.http.response import HttpResponse
from tastypie.exceptions import ImmediateHttpResponse
from tastypie import http
from tastypie.serializers import Serializer
class BaseCorsResource(Resource):
def create_response(self, *args, **kwargs):
response = super(BaseCorsResource, self).create_response(*args, **kwargs)
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Headers'] = 'Content-Type'
return response
def post_list(self, request, **kwargs):
response = super(BaseCorsResource, self).post_list(request, **kwargs)
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Expose-Headers'] = 'Location'
return response
def method_check(self, request, allowed=None):
if allowed is None:
allowed = []
request_method = request.method.lower()
allows = ','.join(map(lambda s: s.upper(), allowed))
if request_method == 'options':
response = HttpResponse(allows)
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Headers'] = 'Content-Type'
response['Access-Control-Allow-Methods'] = "GET, PUT, POST, PATCH"
response['Allow'] = allows
raise ImmediateHttpResponse(response=response)
if not request_method in allowed:
response = http.HttpMethodNotAllowed(allows)
response['Allow'] = allows
raise ImmediateHttpResponse(response=response)
return request_method
class AllBlogSlugResource(BaseCorsResource, ModelResource):
class Meta:
queryset = BlogPost.objects.published()
resource_name = "url"
fields = ['keywords_string', 'slug', 'title']
allowed_methods = ['get']
serializer = Serializer()
class BlogResource(BaseCorsResource, ModelResource):
class Meta:
queryset = BlogPost.objects.published()
resource_name = "blog"
fields = ['keywords_string', 'slug', 'title', 'content', 'description']
allowed_methods = ['get']
serializer = Serializer()
接着便可以很愉快地、危险地跨域。
##Django 与墨颀CMS整合
接着修改了一下代码中configure.json的blogListUrl,以及模块
<div class="l-box blogPosts">
<h2>动 态</h2>
{{#objects}}
<p>
<!--<span class="date">{{created}}</span>-->
<a alt="{{title}}" href="http://www.phodal.com/blog/tag/underscore/feeds/atom/#/blog/%7B%7Bslug%7D%7D">{{title}}</a>
</p>
{{/objects}}
</div>
便可以请求到结果了。
一开始对于可配置的选择是正确的.
##结束
代码见: [https://github.com/gmszone/moqi.mobi/tree/django](https://github.com/gmszone/moqi.mobi/tree/django)
QQ讨论群: 344271543
源码 Github: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi)
构建基于Javascript的移动web CMS——添加jQuery插件2014-07-20T12:55:33+00:002014-07-21T13:34:09.101752+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-add-jquery-plugins/当看到[墨颀 CMS](http://cms.moqi.mobi/)的菜单,变成一个工具栏的时候,变觉得这一切有了意义。于是就继续看看这样一个CMS的边栏是怎么组成的。
##RequireJS与jQuery 插件示例
一个简单的组合示例如下所示,在main.js中添加下面的内容
requirejs.config( {
"shim": {
"jquery-cookie" : ["jquery"]
}
} );
接着在另外的文件中添加
define(["jquery"],
function($){
//添加函数
});
这样我们就可以完成一个简单的插件的添加。
##[墨颀CMS](http://cms.moqi.mobi)添加jQuery插件
###jQuery Sidr
> The best jQuery plugin for creating side menus and the easiest way for doing your menu responsive
这是一个创建响应式侧边栏的最好的也是最简单的工具,于是我们需要下载jQuery.sidr.min.js到目录中,接着修改一下main.js:
require.config({
baseUrl: 'lib/',
paths: {
'text': 'text',
jquery: 'jquery-2.1.1.min',
async: 'require/async',
json: 'require/json',
mdown: 'require/mdown',
router: '../router',
templates: '../templates',
jquerySidr: 'jquery.sidr.min',
markdownConverter : 'require/Markdown.Converter'
},
shim: {
jquerySidr:["jquery"],
underscore: {
exports: '_'
}
}
});
require(['../app'], function(App){
App.initialize();
});
添加jquery.sidr.min到里面。
###jQuery Sidr与RequireJS协作
引用官方的示例代码
$(document).ready(function() {
$('#simple-menu').sidr();
});
我们需要将上面的初始化代码添加到app.js的初始化中,
define([
'jquery',
'underscore',
'backbone',
'router',
'jquerySidr'
], function($, _, Backbone, Router){
var initialize = function(){
$(document).ready(function() {
$('#menu').sidr();
});
Router.initialize();
};
return {
initialize: initialize
};
});
这样打开[墨颀 CMS](http://cms.moqi.mobi)便可以看到最后的效果。
##相关资源
QQ讨论群: 344271543
源码 Github: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi)
构建基于Javascript的移动web CMS——模板2014-07-19T14:13:38+00:002014-11-04T06:32:43.608067+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-generate-html/在上一篇[《构建基于Javascript的移动CMS——Hello,World》](www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms/)讲述了[墨颀 CMS](http://cms.moqi.mobi/)的大概组成,并进行了一个简单的示例,即Hello,World。这一次,我们将把CMS简单的放到一个可以运行的服务器环境中,也就是说我们需要一个简单的运行环境,以便于进行更有意思的东西——添加模板。
##开始之前
###环境准备
####类Unix系统
因为电脑上已经装有python了,这里便用python起一个简单的server,对于GNU/Linux、Mac OS等类unix系统来说,都可以这样运行:
python -m SimpleHTTPServer 8000
####Windows
对于Windows来说,如果你已经装有python的话,那自然是可以用上面的方式运行。如果没有的话,可以试一下``mongoose``,下载一个安装之。
###JS库准备
需要准备的JS库有
- Backbone
- RequireJs的插件text.js
- Mustache
###只想要这次的代码
那么就这样子吧
git@github.com:gmszone/moqi.mobi.git
接着切换到learing分支
git checkout learning
checkout到这个版本
git checkout 62fbdaf
##构建移动web CMS
文件列表如下所示
.
|____app.js
|____backbone.js
|____HomeView.js
|____index.html
|____jquery.js
|____main.js
|____mustache.js
|____require.js
|____router.js
|____text.js
|____underscore.js
在这里有些混乱,但是为了少去其中的一些配置的麻烦,就先这样讲述。
###添加路由
用Backbone的一个目的就在于其的路由功能,于是便添加这样一个js——``router.js``,内容如下所示:
define([
'jquery',
'underscore',
'backbone',
'HomeView.js'
], function($, _, Backbone, HomeView) {
var AppRouter = Backbone.Router.extend({
routes: {
'index': 'homePage',
'*actions': 'homePage'
}
});
var initialize = function() {
var app_router = new AppRouter;
app_router.on('route:homePage', function() {
var homeView = new HomeView();
homeView.render();
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
在这里我们先忽略掉HomeView.js,因为这是下面要讲的,在router.js中,我们定义了一个AppRouter,
- ``index``指向的是在初始化时候定义的homePage,这样就可以将主页转向HomeView.js。
- ``*actions``便是将其他未匹配的都转向homePage。
接着我们需要修改一下``app.js``,让他一运行地时候便可以进入路由选择
define(['jquery', 'underscore', 'router'], function($, _, Router) {
var initialize = function() {
Router.initialize();
};
return {
initialize: initialize
};
});
也就是初始化一下路由。
###创建主页View
使用Mustache的优点在于,后台仅仅只需要提供数据,并在前台提供一个位置。因此我们修改了下HTML
<!DOCTYPE html>
<html>
<head>
<title>My Sample Project</title>
<script data-main="main" src="require.js"></script>
</head>
<body>
<div id="aboutArea">{{project}}</div>
</body>
</html
创建了aboutArea这样一个ID,于是我们便可以很愉快地在HomeView.js中添加project的数据。
define([
'jquery',
'underscore',
'mustache',
'text!/index.html'
], function($, _, Mustache, indexTemplate) {
var HomeView = Backbone.View.extend({
el: $('#aboutArea'),
render: function() {
var data = {
project: "My Sample Project"
};
this.$el.html(Mustache.to_html(indexTemplate, data));
}
});
return HomeView;
});
在HomeView.js中,定义了data这样一个object,代码最终的效果便是用"My Sample Project"替换到HTML中的{{project}}。
这样我们便完成了一个真正意义上的移动web CMS平台的Hello,World,剩下的便是添加一个又一个的脚手架。
##CMS最后的效果
CMS: [http://cms.moqi.mobi/](http://cms.moqi.mobi/)
源码 Github: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi)
QQ讨论群: 344271543
Release版下载[0.2.tar.gz](https://github.com/gmszone/moqi.mobi/archive/0.2.tar.gz)
</html>构建基于Javascript的移动web CMS——Hello,World2014-07-18T14:47:42+00:002014-07-26T12:30:15.727223+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms-simple-example/在一篇[构建基于Javascript的移动web CMS入门——简介](http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms/)中简单的介绍了关于[墨颀CMS](http://cms.moqi.mobi)的一些原理,其极框架组成,于是开始接着应该说明一下这个CMS是如何一步步搭建起来。
##RequireJS 使用
###库及依赖
这里用的是bower的JS来下载库,详细可以参考一下[bower install js使用bower管理js](http://www.phodal.com/blog/use-bower-to-install-js-plugins/) 这篇文章。
需要下载的库有
- RequireJS
- Backbone
- Underscore
- Mustache
- jQuery
###使用RequireJS
引用官网的示例
<!DOCTYPE html>
<html>
<head>
<title>My Sample Project</title>
<!-- data-main attribute tells require.js to load
scripts/main.js after require.js loads. -->
<script data-main="js/main" src="lib/require.js"></script>
</head>
<body>
<h1>My Sample Project</h1>
</body>
</html>
我们需要一个require.js和一个main.js放在同一个目录,在main.js中用使用require()来载入需要加载的脚本。
require.config({
baseUrl: 'lib/',
paths: {
jquery: 'jquery-2.1.1.min'
},
shim: {
underscore: {
exports: '_'
}
}
});
require(['../app'], function(App){
App.initialize();
});
在config中可以配置好其他的库,接着调用了app.js。
define(['jquery', 'underscore'], function($, _){
var initialize = function() {
console.log("Hello World");
}
return {
initialize: initialize
};
});
当打开index.html的时候便会在console中输出``Hello World``。这样我们就完成一个基本的框架,只是还没有HTML,这个将会在下次继续。
##相关资源
QQ讨论群: 344271543
源码 Github: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi)构建基于Javascript的移动web CMS入门——简介2014-07-17T14:15:09+00:002015-03-29T16:11:02.554388+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-jquery-backbone-mustache-build-mobile-app-cms/看到项目上的移动框架,网上寻找了一下,发现原来这些一开始都有。于是,找了个示例开始构建一个移动平台的CMS——[墨颀 CMS](http://cms.moqi.mobi),方便项目深入理解的同时,也可以自己维护一个CMS系统。
##构建框架
尝试过用AngularJS和EmberJS,发现对于使用AngluarJS以及EmberJS来说,主要的问题是要使用自己熟悉的东西没那么容易引入。而且考虑到谷歌向来对自己的项目的支持不是很好~~,所以便放弃了AngluarJS的想法。
于是开始寻找一些方案,但是最后还是选择了一个比较通用的方案。
- RequireJS
- jQuery
- Underscore
- Backbone
相对于AngularJS来说,Backbone是一个轻量级的方案,从大小上来说。对于自己来说,灵活性算是其中好的一点,也就是自己可以随意的加入很多东西。
###关于Backbone
> Backbone.js是一套JavaScript框架与RESTful JSON的应用程式接口。也是一套大致上符合MVC架构的编程范型。Backbone.js以轻量为特色,只需依赖一套Javascript 函式库即可运行。
具体功能上应该是
- Backbone 轻量级,支持jquery,自带路由,对象化视图,强大的sync机制减少页面大小从而加快页面显示。
- jQuery jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用)、events、实现动画效果,并且方便地为网站提供AJAX交互。不过主要是jQuery能够使用户的html页面保持代码和html内容分离,只需定义id即可。
- Underscore是Backbone的依赖库 Underscore 是一个JavaScript实用库,提供了类似Prototype.js的一些功能,但是没有继承任何JavaScript内置对象。
- RequireJS 你可以顺序读取仅需要相关依赖模块。
前台UI,使用的是Pure CSS,一个轻量级的CSS框架,但是最后感觉,总体用到一起,大小还是相当的。只是可以有一个更好的移动体验。
###其他可替换的框架
**AngularJS**,考虑到某些因素,可能会替换掉Backbone,但是还不是当前可行的方案。为了学习是一方案,也为了更好的普及某些东西。
**handlebars** Handlebars 是Mustache的改进,显示与逻辑分离,语法兼容Mustache,可以编译成代码,改进Mustache对路径的支持,但是若需要在服务端运行需要使用服务端Javascript引擎如Node.js。
##项目
前后端分离设计,后台对前台只提供JSON数据,所以在某种意义上来说可能会只适合浏览,和这个要配合后台的框架。总的来说,适合于阅读类的网站。
###源码
代码依然是放在Github上,基本功能已经可以Works了。
[https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi)
###进展及目的
最后目标:构建一个移动平台的CMS系统。
当前:对于这样一个项目来说,目前会考虑优先支持下面的两个框架,
- Django+Tastypie API
- Wordpress
现在:可以从后台读取到数据。
##其他
一些比较好的资料有
- [Organizing your application using Modules](http://backbonetutorials.com/organizing-backbone-using-modules/)
- [Converting an existing Backbone.js project to Require.js](http://ozkatz.github.io/converting-an-existing-backbonejs-project-to-requirejs.html)
##相关资源
QQ讨论群: 344271543
源码 Github: [https://github.com/gmszone/moqi.mobi](https://github.com/gmszone/moqi.mobi)自己动手写编辑器——Lumia Inspired by Atom2014-04-06T01:12:27+00:002016-11-28T01:08:44.642805+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/lumia-editor-diy-yourself-editor/继上一篇 [node webkit 用javascript打造web native](http://www.phodal.com/blog/node-webkit-javascript-build-web-native/)之后,终于算是可以做出一个atom编辑器,只是这里是为了记念一下Nokia的``Lumia``手机,最后代码见[https://github.com/gmszone/lumia](https://github.com/gmszone/lumia)
##开始之前##
需要配置好开发环境,也就是这个,下面是``Mac OS``下的
[https://github.com/rogerwang/node-webkit](https://github.com/rogerwang/node-webkit)
找到对应的版本
将app复制到Application,接着把下面的alias添加到``~/.bash_profile``
# alias to nw
alias nw="/Applications/node-webkit.app/Contents/MacOS/node-webkit"
应用一下
source ~/.bash_profile
启动应用的方式是
nw app.nw
启动之前需要
zip -r app.nw *
这样我们就有了一个基本的框架了
#lumia 0.1#
最初的版本是来自
[https://github.com/zcbenz/nw-sample-apps](https://github.com/zcbenz/nw-sample-apps)
也就是node-webkit官网给的示例
只是这示例看上去一点都不友好,在写这篇文章时Lumia编辑器的截图
<img src="http://www.phodal.com/static/media/uploads/screen_shot_2014-04-06_at_9.21.59_am.jpg" width="600"/>
看上去和atom editor像极了,因为css就是参考atom编辑器的。
##框架组成##
目前主要是由下面两个构成基本的功能
- Node.js
- Node-webkit
- CodeMirror
显然Node-Webkit发挥了主要的功能,但是CodeMirror也功不可没,作为一个在线编辑器的工具,其他目前的工作者。
- Underscore JS扩展库
- StringJS 让对String的处理更加简单
不过Package.json里面有更多的库,但是还没有发挥作用。
##Editor 基本功能##
暂时没有对Node-Webkit的示例做了太多的修改,修改主要基于下面几个部分
- 去除了Save、Open、New三个button,直接改为了快捷键
- 美化UI
- 扩充了匹配,支持更多的语言
- Sublime快捷键绑定
所以,他的基本功能就是
- 打开、保存、新建文件
- 和Sublime一样的快捷键
- Atom一样的外观
- 搜索
##Javascript+HTML+Node-Webkit##
HTML+CSS主要是对界面的美化
```html
<body style="background:#fff">
<div background="#fff" class="workspace">
<div class="horizontal">
<div class="vertical">
<div class="panes">
<div class="pane" style="min-width:100%;">
<ul class="list-inline tab-bar inset-panel" tabindex="-1">
<li class="tab active">
<div class="title" id="title">untitled</div>
<div class="close-icon"></div>
</li>
</ul>
<div class="editor">
<div id="editor"></div>
</div>
</div>
</div>
<div class="status-bar tool-panel panel-bottom">
<div class="flexbox-repaint-hack">
<div class="status-bar-left">
<div class="cursor-position inline-block" id="mode">
<div class="status-image inline-block">
<span class="image-size" style="display: none;"></span>
</div>
</div>
</div>
</div>
</div>
</div>
<input id="newFile" style="display:none;" type="file"/>
<input id="openFile" style="display:none;" type="file"/>
<input id="saveFile" nwsaveas="" style="display:none;" type="file"/>
</div>
<div style="display:none">
<button id="new" style="display:none;">New</button>
<button id="open" style="display:none;">Open</button>
<button id="save" style="display:none;">Save</button>
</div>
</div></body>
```
如把title移到了最上面,变成了和title一样的位置,看上去像极了chrome浏览器的标签,这里主要是用了CSS的伪元素
```css
.tab-bar .tab:before {
content:'';
position: absolute;
top: -1px;
left: -16px;
height: 26px;
width: 30px;
border-top-left-radius: 3px;
border-left: 1px solid #b9b9b9;
box-shadow: inset 1px -1px 1px rgba(0, 0, 0, 0.05);
-webkit-transform: skewX(133deg);
}
.tab-bar:after {
content:"";
position: absolute;
bottom: 0;
height: 5px;
left: 0px;
width: 100%;
background-color: #f0f0f0;
border-bottom: 1px solid #dddddd;
border-top: 1px solid #b9b9b9;
}
```
这些主要就是表现在外见上的,大致上就是上面的作法。
``editor.js``里面做的主要就是判断和处理事件了
```javascript
onload = function() {
newButton = document.getElementById("new");
openButton = document.getElementById("open");
saveButton = document.getElementById("save");
newButton.addEventListener("click", handleNewButton);
openButton.addEventListener("click", handleOpenButton);
saveButton.addEventListener("click", handleSaveButton);
$("#saveFile").change(function(evt) {
onChosenFileToSave($(this).val());
});
$("#openFile").change(function(evt) {
onChosenFileToOpen($(this).val());
});
editor = CodeMirror(
document.getElementById("editor"), {
lineNumbers: true,
keyMap: "sublime",
autoCloseBrackets: true,
matchBrackets: true,
showCursorWhenSelecting: true,
extraKeys: {
"Cmd-N": function(instance) {
handleNewButton()
},
"Ctrl-N": function(instance) {
handleNewButton()
},
"Cmd-O": function(instance) {
handleOpenButton()
},
"Ctrl-O": function(instance) {
handleOpenButton()
},
"Cmd-S": function(instance) {
handleSaveButton()
},
"Ctrl-S": function(instance) {
handleSaveButton()
},
"Cmd-Shift-P": function(instance) {
console.log("hello".green)
}
}
});
newFile();
onresize();
gui.Window.get().show();
};
```
可以看到的是editor主要是由CodeMirror驱动的,还有就是对于语言的判断,这个是用于判断是哪种语言并给予高亮。
```javascript
function handleDocumentChange(title) {
var mode = "javascript";
var modeName = "JavaScript";
if (title) {
title = title.match(/[^/]+$/)[0];
document.getElementById("title").innerHTML = title;
document.title ="Lumia"+title;
_.each(m.allmodes, function(modes) {
if (S(title).contains(modes["filename"])) {
mode = modes["mode"];
modeName = modes["modeName"];
console.log(mode);
}
});
} else {
document.getElementById("title").innerHTML = "[no document loaded]";
}
editor.setOption("mode", mode);
document.getElementById("mode").innerHTML = modeName;
}
```
主要的工作是``underscore``和``stringjs``做的,这里的m用的是外部文件。
```javascript
var m = require('./allmodes')
```underscore 笔记2014-03-19T13:27:51+00:002014-05-14T02:08:00.613635+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/underscore-notes-how-to-user-where-map-last/##underscore _.last##
获取最后几个元素
<pre><code class="javascript">
var data = _.last(content, 10);
</code></pre>
##underscore .map##
获得指定的元素
<pre><code class="javascript">
var data = _.map(
data, function(blog) {
return {
title: blog.title,
slug: blog.slug,
description: blog.description,
keywords: blog.keywords,
created: blog.created
};
});
</code></pre>
##实际应用场景##
这里是因为需要获取最后的十个元素到/blog/page/1上,删去其他无用的元素以提高加载速度
<pre><code class="javascript">
function respages(req, res, next) {
var data = _.last(content, 10);
data = data.reverse();
var data = _.map(
data, function(blog) {
return {
title: blog.title,
slug: blog.slug,
description: blog.description,
keywords: blog.keywords,
created: blog.created
};
});
res.json(data, {
'content-type': 'application/json; charset=utf-8'
});
}
</code></pre>
##undercore _.where##
<blockquote>
遍历list中的每一个值,返回一个数组,这个数组包含包含properties所列出的属性的所有的键 - 值对。
</blockquote>
这里用于url匹配
<pre><code class="javascript">
function resslug(req, res, next) {
var data = _.where(content, {
slug: req.params.slug
});
res.json(data, {
'content-type': 'application/json; charset=utf-8'
});
}
</code></pre>
网站重构,用angularjs做simple app page博客2014-03-19T13:15:40+00:002014-08-18T11:42:48.251591+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/use-angularjs-simple-page-app-blogs/最后效果见 [Phodal's New Homepage][0]
[0]:http://www.phodal.net
这里依赖于angularjs,以及angular route,当然后台是由nodejs+Restify强力驱动~~。
官方示例
[1]:http://docs.angularjs.org/tutorial/step_07
先看看模板是怎样子的
##Blog Lists##
我们将注意力放到blogController上,这样的话我们就知道要在下面放些什么。
<div class="content pure-u-1 pure-u-med-3-4" ng-controller="blogController">
<div class="posts" ng-repeat="post in posts">
<h1 class="content-subhead">Post</h1>
<section class="post">
<header class="post-header">
<h2 class="post-title"><a href="http://www.phodal.com/blog/tag/underscore/feeds/atom/#/blog/%7B%7Bpost.slug%7D%7D">{{post.title}}</a></h2>
<p class="post-meta">
By
<a class="post-author" href="http://www.phodal.com/">Phodal Huang</a>
on
<span class="pure-button pure-button-primary">{{post.created }}</span>
under
<!-- <a class="post-category" ng-class="randomcolors()" href="#" ng-repeat="keyword in post.keywords track by $index">{{keyword}}</a> -->
<a class="post-category" href="http://www.phodal.com/blog/tag/underscore/feeds/atom/" ng-repeat="keyword in post.keywords track by $index">{{keyword}}</a>
</p>
</header>
<div class="post-description">
<p>{{post.description}}</p>
</div>
</section>
</div>
</div>
##Blog Details##
这个就是细节页
<div class="content pure-u-1 pure-u-med-3-4" ng-controller="blogController">
<div>
<div class="posts">
<h1 class="content-subhead">Post</h1>
<section class="post">
<header class="post-header">
<h2 class="post-title">{{post1.title}}</h2>
<p class="post-meta" ng-bind-html="deliberatelyTrustDangerousSnippet()">
</p>
</header>
</section>
</div>
</div>
</div>
##添加路由##
<pre><code class="javascript">
var blogposts = angular.module('blogposts', ['ngRoute']);
blogposts.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'blogslist.html',
controller: 'postlistCtrl'
}).
when('/blog/:slug', {
templateUrl: 'blogsdetails.html',
controller: 'blogController'
});
});
</code></pre>markdown angular,网站重构四,angularjs insert html2014-03-16T06:06:00+00:002015-06-18T06:28:02.391652+00:00Phodal Huanghttp://www.phodal.com/blog/author/root/http://www.phodal.com/blog/markdown-angularjs-underscore-reverse-website-refactory/因为再有的博客基本上是用markdown写的,所以需要将markdown写的博客转为html,再丢给angular处理。
##Markdown##
> Markdown 是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber)和亚伦·斯沃茨(Aaron Swartz)。它允许人们“使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档”。这种语言吸收了很多在电子邮件中已有的纯文本标记的特性。
###安装markdown js##
npm install markdown
简单的用法就是如下面
var markdown = require( "markdown" ).markdown;
console.log( markdown.toHTML( "Hello *World*!" ) );
所以我们要做的就是,声明下markdown,再添加到app.js中
content:markdown.toHTML(row.content),
代码中添加了一个新的元素用于获取最后的十个博客,用的是underscore为的是以后方便,所以最后的app.js代码如下所示
<pre><code class="javascript">
var restify = require('restify');
var _ = require('underscore')._;
var sqlite3 = require('sqlite3').verbose();
var markdown = require( "markdown" ).markdown;
var db = new sqlite3.Database('sqlite3.db');
var server = restify.createServer();
var content = new Array();
server.use(
function crossOrigin(req,res,next){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
return next();
}
);
db.all("SELECT id,content,title,description,slug,created,updated,publish_date,keywords_string FROM blog_blogpost", function(err, rows) {
rows.forEach(function (row) {
content.push({
id:row.id,
slug:row.slug,
description:row.description,
title:row.title,
content:markdown.toHTML(row.content),
keywords:row.keywords_string,
created:row.created,
updated:row.updated,
publish_date:row.publish_date
});
});
function respond(req,res,next){
var data = content[req.params.name-1];
res.json(data, {'content-type': 'application/json; charset=utf-8'});
}
function all(req,res,next){
var data = {blogposts_sum:rows.length};
res.json(data, {'content-type': 'application/json; charset=utf-8'});
}
function respages(req,res,next){
var data = _.last(content,10);
data = data.reverse();
res.json(data, {'content-type': 'application/json; charset=utf-8'});
}
server.get ('/blog',all);
server.get ('/blog/page/:page',respages);
server.head ('/blog/page/:page',respages);
server.get ('/blog/:name',respond);
server.head ('/blog/:name',respond);
db.close();
});
server.listen(10086, function() {
console.log('%s listening at %s', server.name, server.url);
});
</code></pre>
##Angularsjs 插入html###
ng-bind-html
这个指令要引入sanitize 模块
这里似乎需要用到trustAsHtml()这个神奇的东东,看看官方是怎样示例的
[$sanitize][0]
[0]:http://docs.angularjs.org/api/ngSanitize/service/$sanitize
>The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are then serialized back to properly escaped html string. This means that no unsafe input can make it into the returned string, however, since our parser is more strict than a typical browser parser, it's possible that some obscure input, which would be recognized as valid HTML by a browser, won't make it through the sanitizer.
看代码:
<pre><code class="javascript">
function Ctrl($scope, $sce) {
$scope.snippet =
'<p style="color:blue">an html\n' +
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
'snippet</p>';
$scope.deliberatelyTrustDangerousSnippet = function() {
return $sce.trustAsHtml($scope.snippet);
};
}
</code></pre>
以及HTML部分
<pre><div ng-bind-html="deliberatelyTrustDangerousSnippet()">
##整合##
index.html部分
<!DOCTYPE html>
<html lang="en" ng-app="blogposts">
<head>
<meta charset="utf-8"/>
<title>Phodal's New Homepage</title>
<script src="js/angular.min.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-controller="postlistCtrl">
<div class="container-fluid">
<div class="row-fluid">
<div class="span10">
<ul class="posts">
<article ng-repeat="post in posts">
<h1>{{post.title}}</h1>
<p>{{post.description}}</p>
</article>
<article>
<div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div>
</article>
</ul>
</div>
</div>
</div>
</body>
</html>
app.js部分
<pre><code class="javascript">
var blogposts = angular.module('blogposts', []);
blogposts.controller('postlistCtrl', function($scope, $http, $sce) {
$http.get('http://0.0.0.0:10086/blog/page/1').success(function(data) {
$scope.posts = data;
});
$http.get('http://0.0.0.0:10086/blog/1').success(function(data) {
$scope.post1 = data;
console.log(data.content);
$scope.deliberatelyTrustDangerousSnippet = function() {
return $sce.trustAsHtml(data.content);
};
});
});
</code></pre></div></pre>