第一章 建議學習時間8小時·分兩次學習 總項目預計10章javascript
學習方式:詳細閱讀,並手動實現相關代碼(若是沒有node和vue基礎,請學習前面的vue和node基礎博客【共10章】html
演示地址:後臺:demoback.lalalaweb.com 前臺:demo.lalalaweb.com
前端
演示過程當中可能會發現bug,但願即時留言反饋,謝謝vue
源碼下載:https://github.com/sutianbinde/classweb //不是所有的代碼,每次更新博客才更新代碼java
學習目標:此教程將教會你們 如何一步一步實現一個完整的課程學習系統(包括課程管理後臺/Node服務器/學習門戶三個模塊)。node
上次node基礎課程博客你們反響很好,時隔3個月,才更新項目部分,預計2~3天更新一章,我儘可能20天更新完畢,學完這個項目Nodejs和vue就基本熟悉了,如發現教程有誤的地方,請及時留言反饋webpack
視頻教程地址:www.lalalaweb.com,後期會上傳教學視頻,你們可前往視頻學習(暫時尚未視頻)ios
express項目構建 vue-cli項目構建git
咱們首先給項目取一個名字 「在線課堂」 好啦,英文名 classwebgithub
先在本身喜歡的位置 建立項目目錄文件夾 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 mongodb@2.2.33 --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部分都好好再覈對着寫一遍
好啦,今天就講到這裏。下一篇將講解 首頁路由配置,導航,首頁統計信息,用戶添加/修改/刪除,表格組件封裝。
關注公衆號,博客更新便可收到推送