完成的功能
- 阅览文章
- 有作者信息栏
- 根据当前用户判断是否可修改文章
- 修改并保存文章
依赖的第三方工具
- vue.js
- SuMarkdown
- jquery
- bootstrap-taginput
前言
我们先来分析一下这个功能的实现,其实这个过程中是需要很多数据的——作者的数据,文章的数据,当前用户的数据。如果分两个页面来做,显然许多异步数据会被重复加载,所以我决定把这一部分做成一个极小的单页面应用。
同时,在这一次的博客里,用到了许多Vue的重要特性,比如component,directive,life-cycle,是Vue一个不错的示例。
页面代码
主页面代码
<%= title %>
<%include layout/left-bar.ejs%>
<%include layout/alert.ejs%>
阅览模板
{{blog.title}}
发表时间 {{blog.date | toDate }}
字数:{{blog.body.length}}
阅读量:30
编辑模板
前端代码
Directive
/**
* Created by suemi on 14-12-13.
*/
module.exports={
tag:function(Vue){
Vue.directive('tags',{
twoWay:true,
bind: function () {
var self=this;
console.log(self);
$(self.el).on('itemAdded',function(){
scope.blog.tags=$(this).val();
});
$(self.el).on('itemRemoved',function(){
scope.blog.tags=$(this).val();
});
},
update:function(){},
unbind:function(){
$(this.el).off();
}
});
return module.exports;
},
all:function(Vue){
for(var i in module.exports){
if(i==='all') return module.exports;
else module.exports[i](Vue);
}
return module.exports;
}
};
让所有函数返回module.exports可以支持漂亮的链调的写法,同时还写了all函数以实现像angular一样(如下)
angular.module('demo',['app.directives']);
一次加载全部directive
Components
/**
* Created by suemi on 14-12-13.
*/
module.exports={
readBlog:function(Vue){
var scope=Vue.component('readBlog',{
inherit:true,
template:require('../templates/readBlog.html'),
ready:function(){
$('#blogBody').html(marked(this.blog.body));
$('pre code').each(function(i,block){
hljs.highlightBlock(block);
});
},
methods:{
edit:function(){
console.log(this);
this.currentView='editBlog';
}
},
filters:{
toDate:function(date){
var tmp=new Date(date);
return tmp.getFullYear()+'-'+tmp.getMonth()+'-'+tmp.getDate()+' '+tmp.toTimeString().split(' ')[0];
}
}
});
return module.exports;
},
editBlog:function(Vue){
var scope=Vue.component('editBlog',{
inherit:true,
template:require('../templates/editBlog.html'),
ready:function(){
console.log(this.$el);
$.extend(this.myBlog,this.blog);
//复制原文标签
$("input[data-role=tagsinput], select[multiple][data-role=tagsinput]",$(this.$el)).tagsinput();
var tmp=[];
$.extend(tmp,this.blog.tags);
for(var i=0;i
main.js
/**
* Created by suemi on 14-12-13.
*/
hljs.initHighlightingOnLoad();
var Vue=require('vue');
//Vue.config.debug=true;
require('./directives.js').tag(Vue);
require('./components.js').readBlog(Vue).editBlog(Vue);
scope=new Vue({
el:'body',
data:{
user:{
name:'',
avatar:''
},
author:{
avatar:''
description:'',
page:''
},
blog:{
title:'',
tags:[],
body:'',
author:'',
date:undefined,
content:''//html of the blog
},
msg:'',
display:false,
currentView:'readBlog',
editable:true,
login:false
},
methods:{
getAuthor:function(){
var tmp=window.location.href.split('/');
$.get('/getBlog/'+tmp.pop()).done(function(data){
if(data.success){
$.extend(scope.user,data.user);
$.extend(scope.author,data.author);
$.extend(scope.blog,data.blog);
$('#blogBody').html(marked(scope.blog.body));
$('pre code').each(function(){hljs.highlightBlock(this);});
//scope.blog.content=marked(scope.blog.body);
if(scope.user.name!=='') scope.login=true;
if(scope.user.name!==scope.blog.author) scope.editable=false;
}
else window.location.href='/404';
}).fail(function(){
window.location.href='/404';
});
},
}
});
scope.getAuthor();
后端代码
/**
*
* Created by suemi on 14-12-4.
*/
var Err=usf.module.tool.Err,
EndHanler=usf.module.tool.EndHandler,
msg=usf.module.msg,
Then=usf.lib.then,
User=usf.db.def.User,
Blog=usf.db.def.Blog;
function writeBlog(req,res){
req.session.uname='suemi';
if(req.body.author!==req.session.uname)
return res.json({
success:false,
err:new Err('用户名不一致')
});
(new Blog(req.body)).save(function(err){
if(!err) res.json({
success:true,
err:null
});
else res.json({
success:false,
err: new Err('后台错误,稍后再试')
});
});
}
function editBlog(req,res){
Then(function(cont){
if(!req.session.uname) return new Err('未登录');
Blog.findById(req.params.blogID,cont);
}).then(function(cont,doc){
if(!doc) return new Err(msg.BLOG.blogNone);
if(doc.author!==req.session.uname) return new Err('权限不足');
delete req.body._id;
doc=tool.union(doc,req.body);
doc.save(cont);
}).then(function(cont){
res.json({
success:true,
err:null
});
}).fail(EndHandler);
}
function getBlog(req,res){
var tmp={};
tmp.user={};
tmp.author={};
Then(function(cont){
Blog.findById(req.params.blogID,cont);
}).then(function(cont,doc){
if(!doc) return new Err(msg.BLOG.blogNone);
tmp.blog=doc;
User.findOne({username:doc.author},cont);
}).then(function(cont,doc){
if(!doc) return new Err('数据错误');
tmp.author.name=doc.username;
tmp.author=tool.union(tmp.author,doc.profile);
if(req.session.uname) User.findOne({username:req.session.uname},cont);
else cont();
}).then(function(cont,doc){
if(doc){
tmp.user.name=doc.username;
tmp.user=tool.union(tmp.user,doc.profile);
}
res.json({
success:true,
user:tmp.user,
author:tmp.author,
blog:tmp.blog,
err:null
});
}).fail(EndHandler);
}
module.exports= {
writeBlog: writeBlog,
editBlog: editBlog,
getBlog: getBlog
};