打通前後端全棧開發node+vue進階【課程學習系統項目實戰詳細講解】(1):創建項目,完成登錄功能

第一章 建議學習時間8小時·分兩次學習      總項目預計10章

 

學習方式:詳細閱讀,並手動實現相關代碼(如果沒有node和vue基礎,請學習前面的vue和node基礎博客【共10章】

演示地址:後臺:demoback.lalalaweb.com  前臺:demo.lalalaweb.com

演示過程中可能會發現bug,希望即時留言反饋,謝謝

源碼下載:https://github.com/sutianbinde/classweb               //不是全部的代碼,每次更新博客才更新代碼

學習目標:此教程將教會大家 如何一步一步實現一個完整的課程學習系統(包括課程管理後臺/Node服務器/學習門戶三個模塊)。

上次node基礎課程博客大家反響很好,時隔3個月,才更新項目部分,預計2~3天更新一章,我儘量20天更新完畢,學完這個項目Nodejs和vue就基本熟悉了,如發現教程有誤的地方,請及時留言反饋

視頻教程地址:www.lalalaweb.com,後期會上傳教學視頻,大家可前往視頻學習(暫時還沒有視頻)

 

express項目構建  vue-cli項目構建


 我們首先給項目取一個名字  “在線課堂” 好啦,英文名 classweb

先在自己喜歡的位置 創建項目目錄文件夾  classweb

 

創建node項目(這個項目我們採取前後端分離的模式,所以需要分別創建node和vue項目,但都放在classweb中)

進入目錄,運行  express server 生成服務器端項目(server是我們服務端項目的名字)   (這裏注意,得提前安裝node express-generator,學習過前面node基礎的同學這些應該的安裝了的,沒安裝的先學前面的課程)

打開命令行的簡單方法:在文件夾中按住 shift 鼠標右鍵 點擊“在此處打開命令行” / "在此處打開powershell窗口"

先安裝 cnpm 鏡像(它是npm的國內代理,可以使下載速度加快,如果以及安裝了的就不用安裝了),使用如下代碼,安裝完成後測試一下 cnpm -v

npm install -g cnpm --registry=https://registry.npm.taobao.org

 

進入項目,安裝依賴,運行測試一下

 

這樣就運行起來了,在瀏覽器輸入http://localhost:3000/  訪問

上面 Node項目就建好了

 

創建 vue項目

先全局安裝vue-cli

npm install --global vue-cli

這裏注意,我們最好是另外開一個命令行 來執行,因爲開發時前面的Node項目和vue項目要同時運行

 

然後在創建vue項目,使用 vue init webpack vueclient

注意:ESLint選項要選擇no(不然代碼一點不規範就報錯) ,如果選錯了,把vueclient文件夾刪了重新創建一遍即可。

 

 進入項目,安裝依賴,運行

 

 這時候瀏覽器中就自動代開網頁了

 

兩個項目的安裝和測試就完成了

安裝mongodb操作軟件 Robomongo

百度雲鏈接

鏈接:http://pan.baidu.com/s/1jHLSG78 密碼:6dhb

安裝方法參考:https://jingyan.baidu.com/article/9113f81b011ee72b3214c78d.html

 

 鏈接好以後,在nwe connection右鍵  create database   輸入創建 classweb數據庫

 

創建好以後,展開classweb,然後在cloolections右鍵,  create collection 創建一個user表(在彈出框中輸入user),用來放後臺登錄的用戶

 

創建好以後就有user表了,雙擊就能打開user表,現在裏面沒有數據

 

 往裏面添加一條數據,便於以後登錄使用

user右鍵 insert document,然後輸入後面的數據 ,save, (數據用戶名 admin  密碼是 123456 加密後的字段 還有手機號)

 

{
    "name" : "admin",
    "phone" : "13388868886",
    "password" : "4QrcOUm6Wau+VuBX8g+IPg=="
}

 

 

 

然後表中就多了這麼一條數據了

 

實現登錄功能


 首先我們把項目導入 編輯器,我這裏使用的Hbuilder,建議大家也使用這個,因爲項目中nodemodules的文件太多,webstrom或sublimetex都會很卡

然後找到App.vue,去掉多餘示例樣式,只留圖中的部分,這是項目的入口頁面

注:每個項目都有很多文件,大家暫時也不用明白他們都表示什麼意思,等用到的時候我會在用到的地方給大家講解的。

預警:第一次進入項目開發,肯定會有很多報錯,大家一定仔細閱讀步驟,仔細實現代碼,如果報錯,有是英文的看不懂,大家可以試着查一查百度/google,也可以在下邊留言,我看到儘量簡答,不要因爲出錯了難以解決就放棄了,我開始學習的時候也遇到很多不知所措的錯誤,心中會有一萬隻草泥馬奔騰的感覺。

 

 然後在componets文件夾中新建 login.vue 文件

 

在login.vue文件中寫入下面登錄頁面的代碼(實現了基本的登錄佈局,在js中定義就基本的變量和登錄的方法名)

複製代碼

<template>
  <div class="backlogin">
        <div class="login_box">
            <div class="title">後臺登錄</div>
            <div>
                <input class="myinput" type="text" placeholder="手機號/用戶名" v-model="username" />
            </div>
            <div>
                <input @keyup.13="login" class="myinput" type="password" placeholder="口令" v-model="password" />
            </div>
            <div class="login_other">
                <a href="javascript:;">找回密碼</a>
                <input type="checkbox" id="remenberme" /><label for="remenberme">記住我</label>
            </div>
            <button :disabled="disablebtn" class="login" @click="login">{{loginText}}</button>
        </div>
        
  </div>
</template>

<script>
    
    export default {
      name: 'backlogin',
      data () {
        return {
                username:"admin",/*TODO:先預存測試值,以免手動輸入*/
                password:"123456",
                disablebtn:false,
                loginText:"登錄"
        }
      },
      methods:{
            login(){
                
            }
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
    .header{
        height: 60px;
        box-shadow: 0 1px 5px rgba(13,62,73,0.2) ;
    }
    .header img{
        width: 170px;
        margin-top: 12px;
        margin-left: 15px;
        float: left;
    }
    .header span{
        float: left;
        color: #566a80;
        margin: 21px 0 0 20px;
    }
    .login_box{
        width: 320px;
        margin: 50px auto;
    }
    .login_box .myinput{
        width: 100%;
        border: 1px solid #cad3de;
        height: 40px;
        line-height: 40px;
        margin: 5px 0 10px;
        border-radius: 3px;
        padding: 0 10px;
        outline: none;
        box-sizing: border-box;
    }
    .login_box .myinput:focus{
        border: 1px solid #4289dc;
    }
    .login_other{
        overflow: hidden;
    }
    
    .login_other a{
        float: right;
        color: #727f8f;
    }
    .login_other a:hover{
        color: #273444;
    }
    .login_other input, .login_other label{
        float: left;
        color: #727f8f;
    }
    .login_other input{
        margin: 4px 5px 0 0;
    }
    .login{
        box-sizing: border-box;
        border: none 0;
        height: 44px;
        line-height: 44px;
        width: 100%;
        background:#4187db;
        font-size: 16px;
        border-radius: 3px;
        margin-right: 40px;
        transition: all 0.5s ease;
        cursor: pointer;
        outline: none;
        color: #fff;
        margin-top: 15px;
    }
    .login:hover{
        background: #2668b5;
    }
    .login[disabled]{
        opacity: 0.8;
    }
    .login[disabled]:hover{
        background:#4187db;
    }
    .title{
        color: #273444;
        font-size: 1.5em;
        text-align: center;
        margin: 0 0 20px 0;
    }
    
    @media only screen and (max-width: 768px) {
        .login_box{
            width: 280px;
            margin: 50px auto;
        }
    }
</style>

複製代碼

 

 然後修改router文件夾下的index.js文件來配置首頁訪問的組件是login.vue   (這裏獲取組件的時候  @表示src文件夾路徑  所有vue文件的引入都不需要vue後綴,import後的賦值最好統一給大寫)。

 

 這樣我們會發現剛打開的vue項目自動刷新了,展示效果如下圖(如果沒有刷新請查看命令行窗口有無報錯,有報錯就需要修改代碼,修改正確再重啓 npm run dev)

 

ajax請求


 

vue中請求數據,這裏我們使用第三方庫axios,這也是vue作者推薦的,比自帶的http好用很多。

先安裝axios

把原來的服務ctrl+c兩次停掉,然後 運行 cnpm install axios --save 安裝,安裝完成再重新啓動服務。

注:這裏爲什麼要用 --save呢,因爲使用save的話,這個包就會集成到package.json中的,我們上線的時候就能通過npm install去直接安裝了。

 

安裝完成後大家打開package.json,就可以看到裏面多了 axios:版本號

 

 

 然後我們在main.js中添加如下代碼 引入axios,並配置基礎路徑(因爲是跨域請求node端,所以所有請求前面都需要添加node端的基礎地址,以後打包上線的時候需要合併的時候再把這個地址刪掉),文件位置和修改後的代碼如下圖

由於是跨域請求,我們需要配置withCredentials爲true,這樣避免每次都被識別爲新的請求。

說明:在vue中,可以使用代理去實現跨域,但是每次新地址都需要配置,還是比較麻煩,這裏我們採用直接配置跨域,一次配置就可以一勞永逸。

import axios from 'axios';//引入axios組件
axios.defaults.withCredentials=true;  //跨域保存session有用
axios.defaults.baseURL = "http://localhost:3000"; //打包的時候直接刪掉,默認基礎路徑在這裏配置
//將 axios 賦值給 Vue,方便在子組件裏面使用
Vue.prototype.$reqs = axios;

 

 

 然後在Login.vue中寫登錄的具體方法  將如下登錄請求代碼寫在 login方法中,登錄的地址爲 “/users/login” ,這個接口我們一會兒在node中去寫。

複製代碼

                var _this = this;
                this.disablebtn = true;
                this.loginText = "登錄中...";
                //this.$reqs就訪問到了main.js中綁定的axios
                this.$reqs.post("/users/login",{
                        username:this.username,
                        password:this.password
                }).then(function(result){ 
                    //成功
                    console.log(result)
                    _this.disablebtn = false;
                    _this.loginText = "登錄";
                    
                }).catch(function (error) {
                    //失敗
                    _this.disablebtn = false;
                    _this.loginText = "登錄"
                });
                

複製代碼

 

 

然後我們轉到node端

先在routes中創建dbhandler.js文件,寫入下面我們封裝好的mongodb操作方法。增刪改查的具體操作我們在前面的node基礎教程中已經詳細講解了,這是這些方法的封裝,代碼和以前講的封裝有些許差異,大家直接用下面的代碼,不要用以前的。

這些方法這裏直接貢獻給大家,大家就可以不用自己寫了,直接複製就Ok,空了可以好好研究研究

 

複製代碼

var mongo=require("mongodb");
var MongoClient = mongo.MongoClient;
var assert = require('assert');
var url = require('url');
var host="localhost";
var port="27017";
var Urls = 'mongodb://localhost:27017/classweb';
// classweb  ===> 自動創建一個


//add一條數據 
var add = function(db,collections,selector,fn){
  var collection = db.collection(collections);
  collection.insertMany([selector],function(err,result){
    try{
        assert.equal(err,null)
        }catch(e){
      console.log(e);
      result = [];
    };
    
    fn(result);
    db.close();
  });
}
//delete
var deletes = function(db,collections,selector,fn){
  var collection = db.collection(collections);
  collection.deleteOne(selector,function(err,result){
    try{
        assert.equal(err,null);
        assert.notStrictEqual(0,result.result.n);
        }catch(e){
      console.log(e);
      result.result = "";
    };
    
    fn( result.result ? [result.result] : []); //如果沒報錯且返回數據不是0,那麼表示操作成功。
    db.close;
  });
};
//find
var find = function(db,collections,selector,fn){
  //collections="hashtable";
  var collection = db.collection(collections);
  
    collection.find(selector).toArray(function(err,result){
      //console.log(docs);
      try{
        assert.equal(err,null);
      }catch(e){
        console.log(e);
        result = [];
      }
      
      fn(result);
      db.close();
    });

}


//update
var updates = function(db,collections,selector,fn){
  var collection = db.collection(collections);
  
  collection.updateOne(selector[0],selector[1],function(err,result){
      try{
        assert.equal(err,null);
        assert.notStrictEqual(0,result.result.n);
        }catch(e){
      console.log(e);
      result.result = "";
    };
    
    fn( result.result ? [result.result] : []); //如果沒報錯且返回數據不是0,那麼表示操作成功。
    db.close();
  });

}
var methodType = {
    // 項目所需
  login:find,
  //   type ---> 不放在服務器上面
  //  放入到服務器
  //  請求---> 根據傳入進來的請求 數據庫操作
  //  req.query    req.body
  show:find, //後臺部分
  add:add,
  update:updates,
  delete:deletes,
  updatePwd:updates,
  //portal部分
  showCourse:find,
  register:add
};
//主邏輯    服務器  , 請求    --》 
// req.route.path ==》 防止前端的請求 直接操作你的數據庫
module.exports = function(req,res,collections,selector,fn){
  MongoClient.connect(Urls, function(err, db) {
    assert.equal(null, err);
    console.log("Connected correctly to server");
    // 根據 請求的地址來確定是什麼操作  (爲了安全,避免前端直接通過請求url操作數據庫)
    methodType[req.route.path.substr(1)](db,collections,selector,fn);
    
    db.close();
  });

};

複製代碼

 

 然後修改自動生成的 users.js  爲如下代碼

代碼解釋:

引入了express框架,路由router,並且引入了上面封裝的 dbhandler。

crypto是加密包,對傳輸過來的密碼進行加密

post請求使用  post方法接收

handler()調用的是dbhander中的方法,傳入的參數依次 ( req:請求詳細, res:響應信息,  “user”操作的表的名稱, 傳入的查詢數據, 回掉函數)

在dbhander.js中配置了login對應的操作是查詢,返回數據放到數組中。如果數組空,就表示沒查到數據,如果非空,比較密碼是否一致,如果都正確,就返回登錄成功。

最後的module.exports = router是ES6的模塊暴露,前面基礎博客中已經講了,這裏就不贅述了

複製代碼

var express = require('express');
var router = express.Router();
var handler = require('./dbhandler.js');
var crypto = require('crypto');

/* POST users listing. */
//登錄
router.post('/login', function(req, res, next) {
    var md5 = crypto.createHash('md5');
    var password = md5.update(req.body.password).digest('base64');

    handler(req, res, "user", {name: req.body.username},function(data){
        if(data.length===0){
            res.end('{"err":"抱歉,系統中並無該用戶,如有需要,請向管理員申請"}');
        }else if(data[0].password !== password){
            res.end('{"err":"密碼不正確"}');
        }else if(data.length!==0&&data[0].password===password){
            
            req.session.username = req.body.username; //存session
            req.session.password = password;
            
            res.end('{"success":"true"}');
        }
        
    });
    
});

module.exports = router;

複製代碼

 

這樣請求的代碼就寫完了,但是跨域請求 需要在node中也作配置纔可以請求到

修改app.js,在11行左右找到 var app= express(),在其後面添加如下代碼

第二段代碼是服務器端存session的,直接使用express-session模塊(後面會帶着大家安裝),然後添加配置項即可(配置項的說明在備註中)

複製代碼

//跨域  後期刪
app.all('*', function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "http://localhost:8080"); //爲了跨域保持session,所以指定地址,不能用*
    res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    res.header('Access-Control-Allow-Credentials', true); 
    next();
});

複製代碼

複製代碼

//session
var session=require('express-session');
app.use(session({
    secret:'classweb531234',               //設置 session 簽名
    name:'classweb',
    cookie:{maxAge:60*1000*60*24}, // 儲存的時間 24小時
    resave:false,             // 每次請求都重新設置session
    saveUninitialized:true
}));

複製代碼

 

 

 停止Node端服務,安裝mongodb

cnpm install [email protected] --save

 

安裝 express-session

cnpm install express-session --save

 

 重啓服務

 

刷新vue的登錄頁面,點擊登錄

你會發現,控制檯打印出了返回的登錄成功信息,這樣我們的登錄功能就編寫完成了 (常見出錯原因在後面附錄)

 

 附錄:常見報錯


 

 1. 數據庫連接失敗 :

  ①可能mongo未自動啓動,請按基礎教程中的介紹正確啓動mongo (Net start MongoDB) 

   ②數據庫名沒寫對  檢查dbhandler.js中的下圖名字是否和數據庫名稱一樣。

  ③表名稱沒給對 ,檢查user.js 中的表名是否和數據庫中的一致。

 

2.根本鏈接不到地址,在網頁控制檯打印紅色的鏈接失敗

  ①請求地址沒寫對,覈對login.vue中的地址和 node端routes/index.js中的地址是否對上

 

  ②跨域配置不對,請按上面的步驟把 vue部分和node部分都好好再覈對着寫一遍

 

 

 

 

好啦,今天就講到這裏。下一篇將講解 首頁路由配置,導航,首頁統計信息,用戶添加/修改/刪除,表格組件封裝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章