環境搭建
-
利用@vue/cli4創建工程,為兼容element-ui選用vue2.x版本
vue create vue-demo
-
添加element-ui框架
cd vue-demo vue add element
上述命令會安裝element-ui插件,不用在入口
main.js
文件配置如下內容:import ElementUI from 'element-ui import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI)
-
安裝axios庫
npm install axios -S
在入口
main.js
文件配置axios:var axios = require('axios') // 設置請求的基本鏈接,如果需要跨域不能直接設置為服務器接口api //axios.defaults.baseURL = '/api' // 全局注冊axios,之后在組件中通過this.$axios發送請求 Vue.prototype.$axios = axios
創建登錄頁面
-
修改App.vue根組件
<template> <div id="app"> <router-view></router-view> </div> </template>
同路由相匹配的子組件將在
<router-view>
標簽渲染 -
創建Login.vue組件
<template> <body class = "login_bg"> <div class = "login_container"> <el-form ref="LoginForm" :model="LoginForm" label-width="80px"> <h2 class = "login_title">登錄</h2> <el-form-item label="用戶名"> <el-input v-model="LoginForm.username"></el-input> </el-form-item> <el-form-item label="密碼"> <el-input v-model="LoginForm.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click = "login">登錄</el-button> <el-button @click = "goToRegist">注冊</el-button> </el-form-item> </el-form> </div> </body> </template> <script> export default { name: 'Login', data() { return { LoginForm: { username: '', password: '' } } }, methods: { // 登錄 login(){ this.$axios.post('/api/login', `username=${this.LoginForm.username}&password=${this.LoginForm.password}`).then(successResponse => { // 后端發送過來的是 Result 類型數據,判斷 Result.code 即可 if(successResponse.data.code === 200){ // 觸發 store 中的 login() 方法,將 LoginForm.username 字段傳遞給 store 中的 username this.$store.commit('login', this.LoginForm) var path = this.$route.query.redirect this.$router.replace({path: path === '/' || path === undefined ? '/index' : path}) } else { this.$alert(successResponse.data.message, '😔 Failed', { confirmButtonText: '確定' }) } }).catch(failResponse => { }) }, // 進入 regist 界面 goToRegist(){ this.$router.replace({path: '/regist'}) } } } </script> <style scoped> .login_container { border-radius: 20px; background-clip: padding-box; margin: 130px auto; width: 400px; padding: 35px 65px 15px 0px; background: #fff; border: 1px solid #cfc9c9; } .login_title { margin: 0px 0px 40px 75px; text-align: center; color: #505458; font-size: 32px; } </style>
在vue環境中this指向vue實例,但在vue中使用axios發起請求時如果then和catch方法直接傳入非箭頭函數形式的匿名函數時,this將指向undefined。
第一種解決方案:
var _this = this
發送請求前保留this引用,后面使用_this訪問vue實例
第二種解決方案:
在then或catch方法中使用箭頭函數形式的匿名函數
-
使用vuex管理全局狀態
export default new Vuex.Store({ state: { user: { username: window.localStorage.getItem('user') == null ? '' : JSON.parse(window.localStorage.getItem('user')).username } }, mutations: { login(state, data) { state.user = data window.localStorage.setItem('user', JSON.stringify(data)) } }, actions: { }, modules: { } })
如果狀態變化,通過
this.$store.commit
方法修改 -
配置路由
const routes = [ { path: '/index', name: 'Index', component: Index, meta: { requireAuth: true } }, { path: '/login', name: 'Login', component: Login } ]
如果使用嵌套路由,嵌套路由僅表示組件的父子關系,與URL地址無關
-
配置前端路由攔截器
main.js
入口文件設置攔截器:router.beforeEach((to, from, next) => { if (to.meta.requireAuth) { if (store.state.user.username) { next() } else { next({ path: 'login', query: {redirect: to.fullPath} }) } } else { next() } } )
to
表示目標路由對象,form
表示源路由對象,next
應保證邏輯代碼執行完后被調用一次
跨域設置
代理解決跨域的原理是:瀏覽器的同源策略僅限制瀏覽器與服務器交互,服務器與服務器交互不受同源策略影響
根目錄創建vue.config.js
文件,配置如下:
module.exports = {
devServer: {
proxy: { // 跨域支持
"/api": {
target: "http://localhost:8081", //API服務器的地址(后端)
changeOrigin: true, // 虛擬的站點需要更管 origin
pathRewrite: {
//重寫路徑 比如 '/api/aaa/ccc'對應后端接口 '/aaa/ccc'
"^/api": "",
},
},
},
}};
target
表示服務器接口地址
pathRewrite
會重寫地址,比如上面代碼會將發送到/api/login
的請求代理到http://localhost:8081/login
。這樣做的好處是只有/api
開頭的請求會被代理,這樣可以避免靜態資源被代理
設置完代理后,只有從本機發起的請求(同域名、同端口)會被代理。如果axios的baseurl與前端服務器不同源,則axios發起的請求不會被代理,造成跨域失敗