最近比较闲,学了一些杂七杂八的技术,但不知道怎么用,想的是做一个简单的博客项目来练手,不知道能不能坚持下去,现在把项目框架搭建好了
项目技术选择
后端:node+express+mongoose
前端:vue2+vue-router+vue-resource+vuex
mongodb
启动:要使用MongoDB,需要指定一个文件夹让它存放数据,我在D:\MongoDB\
data下建立了一个名为db的文件夹
win+R打开cmd,进入D:\MongoDB\bin目录,执行“mongod –dbpath=D:\MongoDB\data\db”,就会启动MongoDB
启动了MongoDB,我们就可以使用mongo(交互式shell)来管理数据库了
项目结构
前端的目录直接用的vue-cli生成的,我觉得超级方便的,很多配置都不用自己去写。不过可能会用到jquery的一些插件,查了资料,在webpack.base.config里面加入这段,就可以随时随地用jquery了
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
jquery: "jquery",
"window.jQuery": "jquery",
})
],
前端的主入口为main.js
import Vue from 'vue'
import router from "./router/router.js"
import Vuex from 'vuex'
import vueResource from 'vue-resource'
import App from './App'
import store from "./vuex/store.js"
import {sync} from 'vuex-router-sync'
import "bootstrap/dist/js/bootstrap.min.js"
import "bootstrap/dist/css/bootstrap.min.css"
window.$router = router;
window.$resource = vueResource;
sync(store, router);
Vue.use(vueResource);
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
前端路由
/**
* Created by canoe on 2016/11/10.
*/
import Vue from 'vue'
import Router from 'vue-router'
import NProgress from 'nprogress'
import userLogin from './../components/login.vue'
import home from './../components/home.vue'
import myBlog from './../components/blog.vue'
const routes = [{
path: '/login',
name: 'login',
component: userLogin
},
{
path:'/home',
name:'home',
component:home,
},{
path:'/myBlog',
name:'myBlog',
component:myBlog,
},
{
path: '*',
redirect: '/login'
}];
Vue.use(Router);
const router = new Router({
mode: 'history',
base: '/',
routes: routes
});
/**
* 登录状态检查
* */
router.beforeEach((to, from, next) => {
NProgress.start();
if (to.matched.some(to => to.meta.requiresAuth)){
//todo 鉴权
}else{
next()
}
});
router.afterEach(transition => {
NProgress.done();
NProgress.remove();
});
module.exports = router;
vuex 是用来管理状态的,可以用来传递组件之间的通信
vuex 目录
数据流动是单向的
组件可以调用 actions
Actions 是用来分发 mutations 的
只有 mutations 可以修改状态
store 是反应式的,即,状态的变化会在组件内部得到反映
后端NODE
昨天就做了个简单的登录注册。因为我用8080端口监听的前端页面,因此我另外开了个端口6600监听的服务,知道这种方法不好,但是没有经验,暂时这样做吧。因此在调本地接口的时候,遇到了跨域问题,查了下资料,在node里加上
//设置跨域访问
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1');
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
这里再记录下依赖Express 实现post 4种方式提交参数吧,因为当时我也遇到个小问题,就是我post的是application/json型的数据,但是node 里面req.body 为空,后来查了资料,需要bodyParser队请求包进行解析,具体的文章http://yijiebuyi.com/blog/90c...,感觉讲的清晰易懂
后端入口server.js
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var mongoose = require('mongoose');
var config = require('./config/config.js')
var router = require('./router/router.js')
var app = express();
app.use(express.static('dist'));
app.set('port', 6600);
app.use(bodyParser.json({limit: '1mb'})); //这里指定参数使用 json 格式
app.use(bodyParser.urlencoded({
extended: true
}));
//设置跨域访问
app.all('*', function(req, res, next) {
console.log(req.body)
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1');
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
app.get('/getdata', function(req, res) {
res.send({id:req.params.id, name: req.params.password});
});
app.get('/', function (req, res)
{
res.sendFile(__dirname + "/" + "index.html");
});
var db = mongoose.connect(config.database);
db = db.connection;
db.on('open', function (err, doc)
{
console.log('数据库连接成功')
});
db.on('err', function (err, doc)
{
console.log('数据库连接失败')
});
app.use('/api', router)
app.listen(app.get('port'), function (req,res)
{
console.log('Server up: http://localhost:' + app.get('port')+new Date().getTime());
});
把项目框架搭建好了之后,第一步是做登录模块。
界面设计
图片描述
前端实现
<template>
<div class="login-wrap">
<div class="blog-desc">
<h1>蚂蚁窝</h1>
<h4>记录一些感想而已</h4>
</div>
<div class="login-title">
<span>
<a class="login-text" href='#' @click='type="login"'>登录</a>
<b>·</b>
<a class="login-text" href='#' @click='type="reg"'>注册</a>
</span>
</div>
<div class="login-box" v-if='type=="login"'>
<form class="login-form" >
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-user"></i></div>
<input class="form-control" type="text" name='username' placeholder="输入用户名" v-model='login_params.username'>
</div>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-unlock-alt"></i></div>
<input class="form-control" type="password" placeholder="输入密码" name="password" v-model='login_params.password'>
</div>
</div>
<div class="tool-box">
<div class="checkbox remember">
<label>
<input type="checkbox"> 记住我
</label>
</div>
<a href='#' class='forget-pwd'>忘记密码</a>
</div>
<div class="login-tip" v-text="err_login"></div>
<button type="button" class="btn btn-lg btn-block" @click='login()'>登录</button>
</form>
</div>
<!--注册-->
<div class="reg-box" v-if='type=="reg"'>
<form class="reg-form" name='reg-form'>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-user"></i></div>
<input class="form-control" name="username" type="text" placeholder="输入用户名" v-model='reg_params.username'>
</div>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-unlock-alt"></i></div>
<input class="form-control" name="password" type="password" placeholder="输入密码" v-model='reg_params.password'>
</div>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-unlock-alt"></i></div>
<input class="form-control" name="ensure_pwd" type="password" placeholder="确认密码" v-model='reg_params.ensure_pwd'>
</div>
</div>
<div class="form-group">
<label class="radio-inline">
<input type="radio" name="gender" value="1" v-model='reg_params.gender'> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" value="0" v-model='reg_params.gender'> 女
</label>
</div>
<button type="button" class="btn btn-lg btn-block" @click='userReg()'>注册</button>
</form>
</div>
</template>
<script type="text/javascript">
import {appLogin } from './../../vuex/action.js'
export default{
data(){
return{
type:'login',
err_login:'',
login_params:{
},
reg_params:{}
}
},
methods:{
login(){
var _this=this;
var login_params=_this.login_params;
if(login_params.username==''){
_this.err_login='用户名不能为空'
}else if(login_params.password==''){
_this.err_login='密码不能为空'
}else{
_this.$store.dispatch('userLogin',_this.login_params).then(res=>{
//权限信息
localStorage.setItem('authorization',JSON.stringify({
token: res.token,
time: new Date().getTime()
}));
_this.$router.replace({path:"article"})
},res=>{
_this.err_login='用户名或密码错误'
});
}
},
userReg(){
if(this.reg_params.ensure_pwd==this.reg_params.password){
this.$store.dispatch('userReg',this.reg_params);
}else{
}
}
}
}
</script>
<style lang="stylus">
@import "./user.styl";
</style>
action.js,主要是一些行为去触发mutations,然后mutations中去修改状态
import * as types from "./mutation_types.js";
import * as API from "../api/api.js";
import Vue from 'vue'
export const setLoginState=({commit},state)=>{
commit(types.SET_LOGIN_STATUS, state);
};
export const userLogin = ({ commit }, params) =>
{
return new Promise((resolve, reject)=>
{
API.login(params).then(res=>
{
var data=res.data;
Vue.http.headers.common['authorization'] = data.token;
commit(types.SET_LOGIN_STATUS, true);
commit(types.SET_USER_INFO, {userName : params.username});
resolve(data)
}, res=>
{
reject(res.data);
})
})
};
vuex module 中的 longin.js,
import {
SET_LOGIN_STATUS,SET_USER_INFO
} from './../mutation_types.js'
const state = {
isLogin: false,
userInfo: {},
};
const mutations = {
[SET_LOGIN_STATUS](state, status) {
state.isLogin = !!status;
},
[SET_USER_INFO](state,data){
state.userInfo = data;
}
};
export default {
state,
mutations
}
api 设计,用的vue-resource nodejs 端提供restful接口
import Vue from "vue";
import VueResource from "vue-resource"
Vue.use(VueResource);
// HTTP相关
Vue.http.options.crossOrigin = true;
Vue.http.options.credentials = true;
Vue.http.interceptors.push((req, next) =>
{
next((res) =>
{
return res
});
});
const api = {
user : `http://localhost:6600/api/user`,
article:'http://localhost:6600/api/article',
comment:'http://localhost:6600/api/comment',
favorite:'http://localhost:6600/api/favorite',
};
const userResource = Vue.resource(api.user + '{/id}');
const articleResource = Vue.resource(api.article + '{/id}');
const commentResource = Vue.resource(api.comment + '{/id}');
const favoriteResource = Vue.resource(api.favorite + '{/id}');
export const login = function (params)
{
return userResource.save({id : 'userLogin'}, params)
};
export const userReg = function (params)
{
return userResource.save({id : 'userReg'}, params)
};
export const getArticleList = function (params)
{
return articleResource.get(params)
};
export const createArticle=function(params){
return articleResource.save(params)
};
export const getArticleDetail=function(articleId){
return articleResource.get({id:articleId})
};
export const commentArticle=function(params){
return commentResource.save({id:params.id},params)
};
export const favoriteArticle=function(params){
return favoriteResource.save({id:params.id},params)
};
nodejs 端
model 设计
var mongoose=require('mongoose');
var md5 = require("md5");
var Schema=mongoose.Schema;//创建模型
var userSchema=new Schema({
userName:{type:String, require:true},
passWord:{type:String, require:true},
ensure_pwd:{type:String, require:true},
gender:Boolean,//1 为男,0为女
created:{type:Date}
});
var articleSchema=new Schema({
title:{type:String, require:true},
content: {type:String, require:true},
author: {type:Schema.Types.ObjectId, ref:'User'},
//category: {type:Schema.Types.ObjectId, ref:'Category'},
created: {type:Date},
hasRead:{type:Number},
slug: {type:String, required: true },
published: {type:Boolean, default: false },
meta: {type:Schema.Types.Mixed,favorites: 0 },
comments: [Schema.Types.Mixed ]
});
var CategorySchema = new Schema({
name: {type:String, require:true},
slug: {type:String, require:true},
created: {type:Date}
});
//MD5密码和原密码匹配
userSchema.methods.verifyPassword= function(password){
var isMatch= md5(password)=== this.password;
//console.log('UserSchema.methods.verifyPassword: ', password, this.password, isMatch);
return isMatch;
};
var Models={
User:mongoose.model('User',userSchema),
Article:mongoose.model('Article',articleSchema),
Category:mongoose.model('Category',CategorySchema),
}
module.exports = Models;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。