最近比较闲,学了一些杂七杂八的技术,但不知道怎么用,想的是做一个简单的博客项目来练手,不知道能不能坚持下去,现在把项目框架搭建好了

项目技术选择

后端: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)来管理数据库了   

项目结构

clipboard.png

前端的目录直接用的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 目录

clipboard.png

数据流动是单向的

组件可以调用 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;

canoe
57 声望3 粉丝