小白记录成长史,如有错误还请谅解并联系本人,本人会及时更正。
1.安装所需插件
1.1 安装qs
安装qs:
npm install qs
在main.js中全局引用
import qs from 'qs'
Vue.prototype.$qs = qs;
使用时
this.$qs.stringify(obj);
this.$qs.parse(url);
在单页面使用:
import qs from 'qs';
qs.stringify(obj)
qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库。
qs.parse();作用是将URL解析成对象的形式 。qs.stringify();作用是将对象序列化成URL的形式,以&进行拼接。
1.2安装MD5加密
npm安装:npm install --save js-md5
在main.js中全局引用
import md5 from 'js-md5';
Vue.prototype.$md5 = md5;
使用
this.$md5('123456')
单页面使用:port md5 from 'js-md5';
md5('123456')
1.3安装axios
安装:
npm install axios --save
在main.js中全局引用
import axios from 'axios'
Vue.prototype.$axios = axios;
1.4安装vuex
安装:npm install vuex --save
在main.js中引用
import store from './store';
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
1.5安装进度条
npm install --save nprogress
//导入
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
//用法
NProgress.start();
NProgress.done();
2.登陆页面
<template>
<div>
<div style="margin:0 auto;width:30%;">
<el-input placeholder="请输入账号" v-model="userInfo.username" clearable></el-input>
<el-input placeholder="请输入密码" v-model="userInfo.password" clearable style="margin:20px 0;"></el-input>
<el-button size="medium" type="primary" @click="login">登录</el-button>
</div>
</div>
</template>
<script>
export default {
name: "",
props: [""],
data() {
return {
userInfo: {
username: "admin",
password: "123456"
}
};
},
/* 组件 */
components: {},
/* HTML DOM加载后马上执行的,如赋值*/
computed: {},
/* 模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图 */
created() {},
/* 模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作 */
mounted() {},
/* methods则必须要有一定的触发条件才能执行 */
methods: {
//登录
login() {
let that = this;
this.$store
.dispatch("user/login", this.userInfo)
.then(res => {
console.log("按钮", res);
// 登录成功跳转首页
that.$router.push({
path: "/home"
});
})
.catch(res => {});
}
},
/* 观察Vue实例上的数据变动 */
watch: {}
};
</script>
<style lang='' scoped>
</style>
3.请求封装
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import qs from 'qs'
// create an axios instance
const service = axios.create({
baseURL: "/api", // 后台接口地址
timeout: 5000 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
let isLogin = store.getters.token;
let isGet = config.method;
config.params = config.data;
console.log(isGet, "vuex+store", isLogin, config.params);
// get请求方式用qs.stringify(),将对象序列化成URL的形式,以&进行拼接。
if (isGet == "get") qs.stringify(config.params);
// 请求头部Content-Type设置,不然后台接不到参数
// 如果有token请求头带token
config.headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'token': isLogin ? store.getters.token : ""
};
},
error => {
console.log(error)
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
response => {
const res = response.data;
console.log("请求响应", res);
if (res.code === "000000") {
return res.datum || [];
} else {
// 提示弹框展示错误信息
Message({
message: res.reason,
type: 'error',
duration: 5 * 100
})
return Promise.reject(res)
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error,
type: 'error',
duration: 5 * 100
})
return Promise.reject(error)
}
)
export default service
**跨域**
proxyTable: {
'/api': {//这里的api相当于后台地址
target: 'http://后台地址',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
},
4.userApi
import request from '@/utils/request'
let userApi = {};
userApi.login = function (data) {
return request({
url: '/login',
method: 'post',
data
})
}
userApi.logout = function (data) {
console.log("data", data);
return request({
url: "logout",
method: 'get',
data
})
}
export default userApi
5.vuex
5.1新建件夹
5.2store–index.js
公开方法,方便使用
import Vue from 'vue'
import Vuex from 'vuex'
import getters from "./getters"
import user from "./modules/user"
import role from "./modules/role"
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
user,
role,
},
getters
})
export default store
5.3store–getters.js
getters取得state里面的数据,并公开
const getters={
token: state => state.user.token,
userInfo: state => state.user.userInfo,
}
export default getters
5.4store–modules–user.js
import vue from 'vue';
import md5 from 'js-md5';
import userApi from "@/api/userApi"
// 取缓存中数据
let loginData = localStorage.getItem('loginData');
let userInfo = loginData&&JSON.parse(loginData) || {};
console.log("取缓存中数据", userInfo);
const state = {
token: "",
userInfo: userInfo,
}
const mutations = {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_USERINFO: (state, userInfo) => {
state.userInfo = userInfo
},
}
const actions = {
// 登录
login({ commit }, userInfo) {
//赋值解构
const { username, password } = userInfo;
return new Promise((resolve, reject) => {
userApi.login({ username: username.trim(), password: md5(password), loginType: 1 }).then(res => {
console.log("登录成功", res);
commit('SET_TOKEN', res.token);
commit('SET_USERINFO', res);
// 把数据存到缓存中
localStorage.setItem("loginData", JSON.stringify(res));
resolve(res);
}).catch(res => { reject(res) })
})
},
// 退出登录
logout({ commit }) {
//赋值解构
return new Promise((resolve, reject) => {
userApi.logout({ uid: state.userInfo.uid }).then(res => {
console.log("退出登录", res);
//清除token
commit('SET_TOKEN', "");
//清除state里的用户信息
commit('SET_USERINFO', {});
// 清除缓存数据
localStorage.removeItem("loginData");
resolve();
}).catch(res => { reject(res) })
})
},
// 清除用户信息
resetToken({ commit }) {
return new Promise(resolve => {
//清除token
commit('SET_TOKEN', "");
//清除state里的用户信息
commit('SET_USERINFO', {});
// 清除缓存数据
localStorage.removeItem("loginData");
resolve()
})
},
}
export default {
namespaced: true,
state,
mutations,
actions
}
6.vue登录拦截
6.1 permission.js
import router from './router'
import user from './store/modules/user'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { Message } from 'element-ui'
import store from './store'
NProgress.configure({ showSpinner: false })
// 第一种简单拦截
console.log(from, to.path, "======", user.state.token, this);
if (user.state.token) { // vuex.state判断token是否存在
console.log("已登录", to.fullPath);
next() // 已登录
} else {
console.log(to.path, "未登录", to.fullPath);
// 未登录跳转登录页
if (from.path == "/login") {
next()
} else {
next({
path: '/login',
query: { redirect: from.fullPath }
})
}
}
})
// 第二种拦截
const whiteList = ['/login'] // 没有重定向白名单
router.beforeEach(async (to, from, next) => {
console.log('to path: ', to.path, to, 'from path: ', from.path, from);
// 开始进度条
NProgress.start()
// 确定用户是否已登录
if (user.state.token) {
if (to.path === '/login') {
// 如果已登录,请重定向到主页
next({ path: '/home' })
NProgress.done()
} else {
try {
next()
} catch (error) {
// 删除令牌并进入登录页面重新登录
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
} else {
/* 没有token*/
if (whiteList.indexOf(to.path) !== -1) {
// 在登录白名单中,直接进入
next()
} else {
// 其他无权访问的页面将重定向到登录页面。
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
router.afterEach(() => {
// 结束进度条
NProgress.done()
})
6.2 路由
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/login',
name: 'login',
component: () => import('@/views/login/index')
},
{
path: '/home',
name: 'home',
component: () => import('@/views/loginout-demo/index')
},
]
})
7.退出登录
<template>
<div style="margin:0 auto;width:50%;">
<el-button size="medium" type="primary" @click="logout">退出登录</el-button>
</div>
</template>
<script>
export default {
name: "",
props: [""],
data() {
return {
userInfo: {
username: "",
password: ""
}
};
},
/* 组件 */
components: {},
/* HTML DOM加载后马上执行的,如赋值*/
computed: {},
/* 模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图 */
created() {},
/* 模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作 */
mounted() {},
/* methods则必须要有一定的触发条件才能执行 */
methods: {
/**
* 退出登录
*/
logout() {
this.$store
.dispatch("user/logout")
.then(res => {
let getUserInfo = localStorage.getItem("loginData");
//调到首页
this.$router.push(`/login?redirect=${this.$route.fullPath}`);
console.log("按钮", getUserInfo);
})
.catch(res => {});
}
},
/* 观察Vue实例上的数据变动 */
watch: {}
};
</script>
<style lang='' scoped>
</style>
参考文献:
1.https://blog.csdn.net/wn1245343496/article/details/82151273
2.https://blog.csdn.net/xqainyo/article/details/105245826?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2
3.https://www.cnblogs.com/hspl/p/11189088.html
4.https://segmentfault.com/q/1010000010645817