首先bootstrap是依賴於jquery的,因此須要安裝jquery。
一、在下載好jquery以後,須要引入jquery。
在webpack.base.conf.js模塊中,使用webpack的內置模塊ProvidePlugin,能夠自動加載模塊,而不須要使用import等。html
const webpack = require('webpack') plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }) ] //添加好以後,能夠直接找一個頁面測試 //例在HelloWorld.vue添加,審查元素,body中有沒有添加成功 //若是成功者說明引入成功 $("body").append("<div>1</div>");
二、安裝bootstrap,特別提醒若是你安裝jquery的版本是3.3.1,那麼若是安裝的bootstrap的版本是4以上的那麼2者是不兼容的bootstrap的樣式會出現問題,因此我的建議安裝bootstrap3.3.7的。
安裝:npm install --save bootstrap@3.3.7,固然你也能夠直接到官網裏下載。
引用:若是是用npm方式安裝的,那麼記住這個是在node_modules文件中的。
在main.js頭上中引入:前端
import 'bootstrap/css/bootstrap.min.css' import 'bootstrap/js/bootstrap.min.js'
這個時候可能會報Popper.js文件找不到的錯誤,由於這裏bootstrap依賴Popper.js文件,用npm install --save Popper.js
安裝一下就能夠了。vue
剛剛不是說也能夠直接在官網上下載下來的,若是是直接下載的。將下載包移動到你放置靜態文件的文件夾中解壓出來(我比較推薦這種作法,由於這樣比較好管理),通常不會怎麼變化的靜態文件我會存放在「static」目錄下。node
//在`webpack.base.conf.js文件`中alias模塊 //這裏的resolve是一個方法 function resolve (dir) { //join方法用於將多個字符串結合成一個路徑字符串 //path在node中會常常用到能夠仔細瞭解一下path的各類方法 //__dirname:獲取當前文件所在目錄的完整絕對路徑 return path.join(__dirname, '..', dir) } alias: { 'bootstrap':resolve('static/bootstrap'), } //main.js //這裏的bootstrap指代的就是上面的../static/bootstrap import 'bootstrap/css/bootstrap.min.css' import 'bootstrap/js/bootstrap.min.js'
到此開發時的基本樣式框架已經準備完畢。jquery
最終結果:webpack
問題:咱們須要設計若是沒有登入話跳轉登入頁面,若是已經登入過則跳轉home頁面。
首先這個問題須要分2中狀況進行考慮:一、客戶進行訪問時是基於登入的前提下進行的,如管理系統等;二、這個系統不須要一開始就進行登入,只有在特殊的頁面才須要進行登入驗證,例如博客。
若是「這個系統不須要一開始就進行登入,只有在特殊的頁面才須要進行登入驗證」。能夠用vue-router的導航守衛來實現。導航守衛分爲:全局、單個路由和組件級的。關於各類級別的守衛在官網裏已經寫的很詳細了,能夠本身去看。在這裏咱們着重瞭解一下每一個守衛方法接收三個參數:to, from, next。
若是是第一種狀況,能夠用鉤子函數created進行判斷。登入的流程:git
//這是一些路由代碼,下面的參數說明都是依照這段代碼的 import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import Login from '@/login' Vue.use(Router) const router = new Router({ mode: 'history', routes: [ { path: '/', redirect: '/home' //重定向 }, { path: '/home', name: 'HelloWorld', component: HelloWorld }, { path: '/login', name: 'login', component: Login } ] });
next: Function: 必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。一、 next(): 進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是 confirmed (確認的)。二、 next(false): 中斷當前的導航。若是瀏覽器的 URL 改變了(多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。三、 next('/') 或者 next({ path: '/' }): 跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。你能夠向 next 傳遞任意位置對象,且容許設置諸如 replace: true、name: 'home' 之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。三、 next(error): (2.4.0+) 若是傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 註冊過的回調。 確保要調用 next 方法,不然鉤子就不會被 resolved
在vue中請額外注意箭頭函數的運用:注意箭頭行數this指向的是執行時的上下文。例如咱們在methods中定義一個方法,而後這裏面須要訪問data裏面的數據,若是你用同步的方法能夠用this.x訪問到data中的數據,由於這時候this指向的是vue中的上下文,其能夠訪問data定義的數據。若是該方法用箭頭函數定義且你在外邊調用,那麼這時候this指向的是執行時的上下文,這是this並不能訪問定義在vue內部的data。github
//html <button class="btn loginBtn" data-loading-text="Loading..." type="button" @click="doLogin()"> LOGIN</button> //js <script> export default { name: 'login', data () { return { msg: 'Welcome to Login page' } }, methods: { doLogin() { var self = this; console.info(self.msg);//正常訪問,內容爲「Welcome to Login page」 } } } //若是爲箭頭函數 export default { name: 'login', data () { return { msg: 'Welcome to Login page' } }, methods: { doLogin:() => { var self = this; console.info(self.msg);//不能訪問,控制檯打印出「undefined」 } } } </script>
前面咱們說到,在某些頁面須要進行登入驗證。這裏咱們能夠藉助router導航守衛中的全局守衛beforeEachweb
router.beforeEach((to, from, next)=> { ...... })
但這裏咱們須要區別跳轉頁面時,那個頁面是須要驗證的那個是不要的。咱們能夠直接在定義路由的時候就指出須要驗證的地址,設置meta:{requireAuth: true },而後在beforeEach中判斷to.meta.requireAuth是否爲true,若是爲true則須要驗證。代碼以下:
//router文件下的index.js import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld'//這裏特別說明一下@這個東西,在webpack配置文件中的resolve下面alias設置了@表明‘src’路徑。具體webpack配置的問題我在前面的幾章也說過。 import Login from '@/login' Vue.use(Router) const router = new Router({ mode: 'history', routes: [ { path: '/', redirect: '/home' //重定向 }, { path: '/home', name: 'HelloWorld', component: HelloWorld, meta:{requireAuth: true } }, { path: '/login', name: 'login', component: Login } ] }); router.beforeEach((to, from, next)=> { if(to.meta.requireAuth) { .... } next(); }) export default router;
而後知道那個頁面須要驗證後咱們須要經過cookie來獲取session判斷是否已經登入過。首先咱們須要封裝一下cookie。在src下新建文件夾util,在util下新建cookie.js
//獲取cookie export function getCookie(name) { var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)") if(arr = document.cookie.match(reg)) { return arr[2]; }else { return null; } } //設置cookie export function setCookie(c_name, value, expiredays) { const exdate = new Date(); exdate.setDate(exdate.getDate() + expiredays); document.cookie = c_name + '=' + escape(value) + ((expiredays == null) ? "": ';expires='+exdate.toGMTString()) } //刪除cookie export function delCookie (name) { var exp = new Date(); exp.setTime(exp.getTime() - 1); var cval = getCookie(name); if (cval != null) document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString(); }
而後在router/index.js引入cookie.jsimport {delCookie,getCookie} from '@/util/cookie'
,最終router/index.js變成
...... import {delCookie,getCookie} from '@/util/cookie' ...... router.beforeEach((to, from, next)=> { if(to.meta.requireAuth) { if(getCookie('session')) { next(); }else { next({ path: '/login' }); } } next(); })
而後在main.js中引入router
import Vue from 'vue' import App from './App' import router from './router' import 'bootstrap/css/bootstrap.min.css'//這裏的bootstrap同上的@ import 'bootstrap/js/bootstrap.min.js' Vue.config.productionTip = false new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
我默認你知道如何操做vuex,若是不知道的能夠看這裏,我以爲寫得十分通俗易懂,我就不具體說了。在src下建好store以後須要在main.js中引用並使用。
//main.js ...... import store from '@/store' ...... new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
//login.vue html <template> <div class="login"> <div class="logo"> <img src="./assets/bog-logo.png" height="200px"> <h1>{{ msg }}</h1> </div> <div class="content"> <form class="loginForm"> <input type="text" v-model= "loginForm.userName" class="form-control" placeholder="Plass enter your username"> <input type="password" v-model= "loginForm.password" class="form-control" placeholder="Plass enter your password"> <button class="btn loginBtn" data-loading-text="Loading..." type="button" @click="doLogin()"> LOGIN</button> <button class="btn enrollBtn" data-loading-text="Enroll..." type="button"> 註冊</button> </form> </div> </div> </template> <style scoped> .login { width: 100%; height: 100%; } .logo {color: #53538f;} .content {margin:0 auto;background: #e2e2f6;width: 50%;;max-width: 500px;padding: 30px; border-radius: 10px} .loginForm {margin:0 auto;} .loginForm .form-control {margin:10px 0;height: 50px;} .loginForm .loginBtn,.enrollBtn {background: #53538F;color: #fff;font-size: 20px;} .enrollBtn {background: #f5c7bc;font-size: 12px;} </style>
//js export default { name: 'login', data () { return { msg: 'Welcome to Login page', loginForm: { userName: '', password: '' } } }, methods: { doLogin() { const _self = this; const loginForm = _self.loginForm; const api = _self.$store.state.api;//這裏的api就是定義在vuex中,這樣全部的組件均可以訪問,而且之後修改的話只須要修改一處就行 if(loginForm.userName == '' || loginForm.password == '') { alert("用戶名或密碼不能爲空!") return ; } $(".loginBtn").button('loading'); $(".enrollBtn").hide(500); $.post(api + '/doLogin', loginForm, function(result){ if(!result.success) { alert(result.msg); $(".loginBtn").button('reset'); $(".enrollBtn").show(500); return ; } }); } } } </script>
這裏我是用node作了一個簡單的後臺服務器,因此涉及到跨域的問題,我先用了極其簡單的方法解決。後臺代碼都放在了serve文件夾中。在app.js中設置header和訪問路徑,並返回結果。
.......... //設置跨域訪問 app.all('*', function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); 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.post('/doLogin',function(req,res){ const user = { "admin":'123456' }; const vUser = req.body; var result = {}; if(!user.hasOwnProperty(vUser.userName)) { result["success"] = false result["msg"] = "不存在該用戶!" }else { result["success"] = true result["msg"] = "登入成功!" if(user[vUser.userName] != vUser.password){ result["success"] = false result["msg"] = "密碼不正確!" } } res.send(result); }) ;
登入成功後,利用crypto加密用戶名,生成token返回前端,存儲到cookie中。由於模塊有可能會比較多,因此我就將user模塊分離出來了。最後服務器代碼,先在serve下建一個名叫routes的文件夾,全部路徑都放在這裏。先建一個index.js
const photos = require('./photos'); const user = require('./user');//引入user相關的操做 /* * GET home page. */ exports.index = function(req, res){ res.render('index', { title: 'Express' }); }; /* * GET photo page. */ exports.photos = photos; exports.user = user;
具體的crypto屬性方法能夠參考官網。但這裏我發現一個問題,我也不知道爲何。若是createHmac寫在上頭第二次操做的時候就會報「HashUpdate fail」。若是有知道的請告知我一下。
//新建user.js文件 const crypto = require('crypto');//nodejs的內置模塊 加密 //const hmac = crypto.createHmac('sha256', 'blogsss');若是這樣寫,再第二次操做的時候就會報」HashUpdate fail「 /* * GET users listing. */ const user = { "admin":'123456' }; exports.doLogin = function(req, res, next){ const vUser = req.body; var result = {}; if(!user.hasOwnProperty(vUser.userName)) { result["success"] = false result["msg"] = "不存在該用戶!" }else { result["success"] = false result["msg"] = "密碼不正確!" if(user[vUser.userName] == vUser.password){ //const hash = hmac.update(vUser.userName+"date="+new Date()).digest('hex'); const hash = crypto.createHmac('sha256', 'blogsss').update(vUser.userName+"date="+new Date()).digest('hex'); result["success"] = true result["msg"] = "登入成功!" result["token"] = hash } } res.send(result); };
登入成功以後除了要將返回的token存儲之外還需將vuex的一些用戶信息修改,而且跳轉home頁面。這裏須要修改的時候,要在login頁面引入3個mapGetters, mapMutations, mapActions。但這裏我只須要mapActions因此只引入了mapActions。
//login.vue <script> import {mapActions} from 'vuex'; import {getCookie, setCookie} from '@/util/cookie' export default { .... methods: { ...mapActions([ 'updateUserInfo'//注意這裏須要加單引號,以前參考的文檔中沒有,因此一直報updateUserInfo未定義的錯誤 ]), doLogin() { const _self = this; const loginForm = _self.loginForm; const api = _self.$store.state.api; if(loginForm.userName == '' || loginForm.password == '') { alert("用戶名或密碼不能爲空!") return ; } $(".loginBtn").button('loading'); $(".enrollBtn").hide(500); $.post(api + '/doLogin', loginForm, function(result){ if(!result.success) { alert(result.msg); $(".loginBtn").button('reset'); $(".enrollBtn").show(500); return ; }else { setCookie("session", result.token, 2); _self.updateUserInfo({//修改vuex的值 name:loginForm.userName, login:true }); _self.$router.push('/home'); } }); } } } </script>
這裏須要注意的是vuex的actions,它只能傳一個參數,若是有2個後面的就undefined了,因此我這裏解決的方法是傳一個對象進去。
//store/actions.js import * as types from './mutation-type.js'; export default { updateUserInfo({commit}, obj) { commit(types.SET_USERNAME, obj.name); commit(types.SET_LOGIN, obj.login); } };
這樣該存的存,該改的改以後用this.$router.push('/home')
咱們跳轉到home頁面了。