最近作項目,須要登陸攔截,驗證。因而使用了axios的攔截器(也是第一次使用,摸索了1天,終於搞出來了,真是過高興啦!!!),廢話很少說,直接上代碼,vue
項目結構:vue-cli + webpack + vue + vue-router + vuexwebpack
項目結構截圖:ios
其中src下store文件夾中有兩個文件,store.js和type.js,其中store.js爲:git
1 /** 2 * Created by yuwenjing on 17/9/13. 3 */ 4 import Vuex from 'vuex' 5 import Vue from 'vue' 6 import * as types from './types' 7 8 Vue.use(Vuex); 9 export default new Vuex.Store({ 10 state: { 11 token: null, 12 userName: '' 13 }, 14 mutations: { 15 [types.LOGIN]: (state, data) => { 16 localStorage.token = data; 17 state.token = data; 18 }, 19 [types.LOGOUT]: (state) => { 20 localStorage.removeItem('token'); 21 state.token = null 22 }, 23 [types.USERNAME]: (state, data) => { 24 localStorage.userName = data; 25 state.userName = data; 26 } 27 } 28 })
types.js爲:github
1 /** 2 * Created by yuwenjing on 17/9/13. 3 * vuex types 4 */ 5 6 export const LOGIN = 'login'; 7 8 export const LOGOUT = 'logout'; 9 10 export const USERNAME = 'userName'
主要業務代碼結構:web
其中main.js爲:vue-router
1 // The Vue build version to load with the `import` command 2 // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 import Vue from 'vue' 4 import App from './App' 5 import store from './store/store' 6 import * as types from './store/types' 7 import router from './router' 8 import axios from 'axios' 9 10 Vue.config.productionTip = false 11 //建立axios實例 12 var $http = axios.create({}); 13 14 // http request 攔截器 15 $http.interceptors.request.use( 16 config => { 17 if(config.url.indexOf('loginCheck')>=0){ 18 return config; 19 }else{ 20 if (store.state.token) { 21 config.headers.authorization = store.state.token; 22 } 23 return config; 24 } 25 26 }, 27 err => { 28 return Promise.reject(err); 29 }); 30 31 // http response 攔截器 32 $http.interceptors.response.use( 33 response => { 34 return response; 35 }, 36 error => { 37 if (error.response) { 38 switch (error.response.data.message) { 39 case "false": 40 // 清除token信息並跳轉到登陸頁面 41 store.commit(types.LOGOUT); 42 router.replace({ 43 path: '/' 44 }) 45 } 46 } 47 // console.log(JSON.stringify(error));//console : Error: Request failed with status code 402 48 return Promise.reject(error.response.data) 49 }); 50 51 Vue.prototype.$http = $http 52 53 /* eslint-disable no-new */ 54 new Vue({ 55 el: '#app', 56 store, 57 router, 58 $http, 59 template: '<App/>', 60 components: { App } 61 })
router文件夾下index.js爲:vuex
1 import Vue from 'vue' 2 import Router from 'vue-router' 3 import login from '@/components/login' 4 import homePage from '@/components/homePage' 5 import store from '../store/store' 6 import * as types from '../store/types' 7 8 Vue.use(Router) 9 10 const routes = [ 11 { 12 path:'/', 13 component:login 14 }, 15 { 16 path: '/homePage', 17 meta: { 18 requireAuth: true, 19 }, 20 component: homePage 21 } 22 ]; 23 24 // 頁面刷新時,從新賦值token,用戶名也在界面上展現 25 if (window.localStorage.getItem('token')) { 26 store.commit(types.LOGIN, window.localStorage.getItem('token')); 27 } 28 if(window.localStorage.getItem('userName')){ 29 store.commit(types.USERNAME, window.localStorage.getItem('userName')); 30 } 31 32 const router = new Router({ 33 routes 34 }); 35 36 router.beforeEach((to, from, next) => { 37 if (to.matched.some(r => r.meta.requireAuth)) { 38 if (store.state.token) { 39 next(); 40 } 41 else { 42 next({ 43 path: '/' 44 }) 45 } 46 } 47 else { 48 next(); 49 } 50 }) 51 52 export default router;
登陸界面login.vue代碼爲:vue-cli
1 <template> 2 <div class="login-wrapper"> 3 <!--頂部--> 4 <div class="top"> 5 <span class="content"> 6 <img src="../../static/img/login_logo.png" class="system-logo"> 7 <span class="system-name">北京熱力面積投停管理系統</span> 8 </span> 9 </div> 10 <!--頂部結束--> 11 12 <!--中部--> 13 <div class="center"> 14 <div class="login"> 15 16 <!--中部左側--> 17 <div class="left"> 18 <img src="../../static/img/login_city.png"> 19 </div> 20 <!--中部左側結束--> 21 22 <!--中部右側--> 23 <div class="right"> 24 25 26 <span class="login-title">用戶登陸</span> 27 28 <!--用戶名輸入--> 29 <div class="username-wrapper"> 30 <i class="username-logo"></i> 31 <input type="text" class="username" placeholder="用戶名" v-model="username" ref="username" @focus="usernameFocus" :class="{'username-focus': isUsernameFocus}"> 32 </div> 33 <!--用戶名輸入結束--> 34 35 <!--密碼輸入--> 36 <div class="pwd-wrapper"> 37 <i class="pwd-logo"></i> 38 <input type="password" class="pwd" placeholder="密碼" v-model="pwd" ref="pwd" @focus="pwdFocus" :class="{'pwd-focus': isPwdFocus}"> 39 </div> 40 <!--密碼輸入結束--> 41 42 <!--提交按鈕--> 43 <button class="login-btn" @click="clickLoginBtn">登陸</button> 44 <!--提交按鈕結束--> 45 </div> 46 <!--中部右側結束--> 47 </div> 48 </div> 49 <!--中部結束--> 50 51 <!--底部--> 52 <div class="bottom"></div> 53 <!--底部結束--> 54 55 </div> 56 </template> 57 58 <script type="text/ecmascript-6"> 59 import * as types from '../store/types' 60 import {SWAGGER_CONFIG} from '../config/config' 61 export default { 62 data() { 63 return { 64 // 用戶名密碼 65 username: '', 66 pwd: '', 67 isUsernameFocus: true, 68 isPwdFocus: false 69 } 70 }, 71 72 methods: { 73 // 點擊登陸按鈕 74 clickLoginBtn() { 75 if (this.username && this.pwd) { 76 this.requestLoginInterface(); 77 } else { 78 alert('用戶名或密碼不能爲空'); 79 } 80 }, 81 82 // 請求登陸接口數據 83 requestLoginInterface () { 84 var self = this; 85 self.$http.post(SWAGGER_CONFIG+'/Ddaas/userrole/loginCheck', 86 { 87 "userName":self.username, 88 "passWord":self.pwd 89 } 90 ).then(function (response) { 91 if(response.data.data == false){ 92 alert("用戶名或密碼不匹配!") 93 return; 94 }else{ 95 self.$store.commit(types.USERNAME,self.username); 96 self.$store.commit(types.LOGIN, response.data.data); 97 self.$router.push({path:"/homePage"}); 98 } 99 }) 100 .catch(function (error) { 101 console.log(error); 102 }); 103 }, 104 105 usernameFocus () { 106 this.isUsernameFocus = true; 107 this.isPwdFocus = false; 108 }, 109 110 pwdFocus() { 111 this.isUsernameFocus = false; 112 this.isPwdFocus = true; 113 } 114 }, 115 116 mounted () { 117 // 掛在成功就聚焦輸入框 118 this.$refs.username.focus(); 119 } 120 } 121 122 </script> 123 124 <style scoped> 125 .login-wrapper { 126 width: 100%; 127 height: 100%; 128 min-width: 700px; 129 min-height: 750px; 130 } 131 132 .login-wrapper .top { 133 width: 100%; 134 height: 22%; 135 display: flex; 136 align-items: center; 137 } 138 139 .login-wrapper .top .content { 140 display: block; 141 width: 100%; 142 height: 61px; 143 text-align: center; 144 } 145 146 .login-wrapper .top .content .system-logo { 147 vertical-align: top; 148 } 149 150 .login-wrapper .top .content .system-name { 151 font-size: 30px; 152 line-height: 61px; 153 color: #077fb7 154 } 155 156 .center { 157 width: 100%; 158 height: 56%; 159 background: linear-gradient(to bottom, #057fbf, #1697d4); 160 /*text-align: center;*/ 161 display: flex; 162 justify-content: center; 163 align-items: center; 164 } 165 166 .center .login { 167 width: 52%; 168 height: 68%; 169 background-color: white; 170 border-radius: 5px; 171 border: 15px solid white; 172 box-shadow: 0 0 0 7px rgba(139, 208, 255, 0.5); 173 } 174 175 .center .login .left { 176 width: 60%; 177 height: 100%; 178 box-sizing: border-box; 179 float: left; 180 } 181 182 .center .login .right { 183 float: right; 184 width: 40%; 185 height: 100%; 186 padding: 22px 8px 30px 22px; 187 } 188 189 .center .login .right .login-title { 190 display: block; 191 width: 100%; 192 height: 24px; 193 font-size: 24px; 194 text-align: center; 195 line-height: 24px; 196 vertical-align: middle; 197 } 198 199 .center .login .right .username-wrapper { 200 position: relative; 201 } 202 203 .center .login .right .username-logo { 204 display: inline-block; 205 position: absolute; 206 top: 12px; 207 left: 10px; 208 width: 14px; 209 height: 14px; 210 background: url('../../static/img/login_user.png') no-repeat; 211 } 212 213 .center .login .right .username { 214 display: block; 215 width: 100%; 216 height: 40px; 217 margin-top: 25px; 218 outline: none; 219 padding-left: 34px; 220 border: 1px solid #e2e7eb; 221 color: #404040; 222 } 223 224 .center .login .right .username-focus { 225 display: block; 226 width: 100%; 227 height: 40px; 228 margin-top: 25px; 229 outline: none; 230 padding-left: 34px; 231 border: 1px solid #0782bb; 232 color: #404040; 233 } 234 235 .center .login .right .username::-webkit-input-placeholder { 236 color: #d2d2d2; 237 } 238 239 .center .login .right .username:-moz-placeholder { 240 color: #d2d2d2; 241 } 242 243 .center .login .right .username:-ms-input-placeholder { 244 color: #d2d2d2; 245 } 246 247 .center .login .right .pwd-wrapper { 248 position: relative; 249 } 250 251 .center .login .right .pwd-logo { 252 display: inline-block; 253 position: absolute; 254 top: 12px; 255 left: 10px; 256 width: 14px; 257 height: 15px; 258 background: url('../../static/img/login_pwd.png') no-repeat; 259 } 260 261 .center .login .right .pwd { 262 display: block; 263 width: 100%; 264 height: 40px; 265 margin-top: 25px; 266 outline: none; 267 padding-left: 34px; 268 border: 1px solid #e2e7eb; 269 color: #404040; 270 } 271 272 .center .login .right .pwd-focus { 273 display: block; 274 width: 100%; 275 height: 40px; 276 margin-top: 25px; 277 outline: none; 278 padding-left: 34px; 279 border: 1px solid #0782bb; 280 color: #404040; 281 } 282 283 .center .login .right .pwd::-webkit-input-placeholder { 284 color: #d2d2d2; 285 } 286 287 .center .login .right .pwd:-moz-placeholder { 288 color: #d2d2d2; 289 } 290 291 .center .login .right .pwd:-ms-input-placeholder { 292 color: #d2d2d2; 293 } 294 295 .center .login .right .login-btn { 296 display: block; 297 width: 100%; 298 height: 40px; 299 margin-top: 30px; 300 background: linear-gradient(to bottom, #1799d6, #047db5); 301 border: none; 302 color: white; 303 font-size: 20px; 304 outline: none; 305 } 306 307 .center .login .left img { 308 width: 100%; 309 height: 100%; 310 } 311 312 .bottom { 313 width: 100%; 314 height: 22%; 315 } 316 </style>
展現用戶名和註銷功能都在headTop.vue中,headTop.vue爲:axios
1 <template> 2 <div id="all"> 3 <div class="top-left"> 4 <p> 5 <img src="../../../static/img/BJRLLOGO.png"> 6 <span>北京熱力面積投停管理系統</span> 7 </p> 8 </div> 9 <div class="top-right"> 10 11 <div> 12 <ul class="first-ul"> 13 <li class="first-li"> 14 <img src="../../../static/img/index.png" class="base-img"> 15 <span class="nav-span">首頁</span> 16 </li> 17 <li class="dropdown"> 18 <img src="../../../static/img/user.png"> 19 <span class="dropdown-toggle nav-span" data-toggle="dropdown"> 20 {{userName}} 21 <!--<b class="caret"></b>--> 22 <img src="../../../static/img/userxiala.png"> 23 </span> 24 <ul class="dropdown-menu"> 25 <li> 26 <img src="../../../static/img/qiehuan.png"> 27 <span>切換帳號</span> 28 </li> 29 <li> 30 <img src="../../../static/img/xiugai.png"> 31 <span>修改密碼</span> 32 </li> 33 34 <li> 35 <img src="../../../static/img/tuichu.png"> 36 <span @click="logout">退出登陸</span> 37 </li> 38 39 </ul> 40 </li> 41 </ul> 42 </div> 43 44 45 </div> 46 47 </div> 48 </template> 49 <style scoped> 50 #all{ 51 width:100%; 52 height:100%; 53 background: #0A86C0; 54 } 55 .top-left{ 56 width:50%; 57 height:100%; 58 float:left; 59 display: table; 60 } 61 .top-left p{ 62 display: table-cell; 63 vertical-align: middle; 64 } 65 .top-left img{ 66 width:auto; 67 height:auto; 68 max-width: 100%; 69 max-height: 100%; 70 margin-left: 2%; 71 } 72 .top-left span{ 73 display: inline-block; 74 color:#fff; 75 font-size: 1.3vw; 76 font-weight: bold; 77 font-family: "Microsoft YaHei UI"; 78 } 79 .top-right{ 80 width:50%; 81 height:100%; 82 float:left; 83 } 84 .top-right div{ 85 width:100%; 86 height:100%; 87 position: relative; 88 display: table; 89 } 90 .first-ul{ 91 list-style: none; 92 position: absolute; 93 right:2%; 94 top:36%; 95 width:27%; 96 } 97 .first-ul>li{ 98 display: inline; 99 } 100 .dropdown-menu li{ 101 text-align: center; 102 } 103 .nav-span{ 104 color:#fff; 105 font-size: 0.8vw; 106 font-family: "Microsoft YaHei UI"; 107 cursor: pointer; 108 } 109 .dropdown-menu{ 110 min-width: 98px; 111 } 112 .dropdown-menu li{ 113 margin-top:6%; 114 } 115 .dropdown-menu span{ 116 font-size: 0.6vw; 117 font-family: "Microsoft YaHei UI"; 118 cursor: pointer; 119 color:#121212; 120 } 121 .first-li{ 122 margin-right: 20%; 123 } 124 .base-img{ 125 vertical-align: text-top; 126 } 127 </style> 128 <script> 129 import * as types from '../../store/types' 130 import {mapState} from 'vuex' 131 export default{ 132 data(){ 133 return{ 134 135 } 136 }, 137 methods:{ 138 logout(){ 139 var self = this; 140 self.$store.commit(types.LOGOUT) 141 self.$router.push({ 142 path: '/' 143 }) 144 145 } 146 147 }, 148 computed: mapState({ 149 userName: state => state.userName 150 }) 151 152 } 153 </script>
要說一句,就是vuex中的state裏的值在頁面刷新的時候會消失(即vuex中的狀態管理是響應式的),所以咱們使用localStorage來解決這個問題
這就是爲何這麼麻煩在state和localStorage中傳來傳去,是由於state的值刷新後會沒了,而localStorage的值不能響應式地變化(Vue 僅能夠對其管理的數據作響應式處理,能夠理解爲 data 中的數據,localStorage 並不在 Vue 的管理下,天然不會有響應特性);
完整的項目地址爲: