刷新页面时vue实例重新加载,store就会被重置,可以把定义刷新前把store存入本地localstorage、sessionstorage、cookie中,localstorage是永久储存,重新打开页面时会读取上一次打开的页面数据,sessionstorage是储存到关闭为止,cookie不适合存大量数据。根据我的需求,最合适的是sessionstorage。
beforeunload在页面刷新时触发,可以监听这个方法,让页面在刷新前存store到sessionstorage中。
当然,在页面刷新时还要读取sessionstorage中的数据到store中,读取和储存都写在app.vue中。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
export default {
name: 'app' ,
created () {
// 在页面加载时读取sessionstorage
if (sessionstorage.getitem( 'store' )) {
this .$store.replacestate(object.assign({}, this .$store.state, json.parse(sessionstorage.getitem( 'store' ))))
}
// 在页面刷新时将store保存到sessionstorage里
window.addeventlistener( 'beforeunload' , () => {
sessionstorage.setitem( 'store' , json.stringify( this .$store.state))
})
}
}
|
补充知识:vue项目将token存在(vuex)store和localstorage中
一、准备工作和token
1、准备工作
了解(session,cookie)token
token的引入:token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,token便应运而生。
token 是在服务端产生的一串字符串,以作客户端进行请求的一个令牌。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 token 给前端。前端可以在每次请求的时候带上 token 证明自己的合法地位。如果这个 token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌(除非设置了有效期)。
token 优点
token 完全由应用管理,所以它可以避开同源策略
token 可以避免 csrf 攻击
token 可以是无状态的,可以在多个服务间共享
减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
安装vuex
cnpm install vuex --save
2、介绍token用法
在前后端完全分离的情况下,vue项目中实现token验证大致思路如下:
1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码
2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token
3、前端拿到token,将token存储到localstorage和vuex中,并跳转路由页面
4、前端每次跳转路由,就判断 localstroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面
5、每次调后端接口,都要在请求头中加token
6、后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401
7、如果前端拿到状态码为401,就清除token信息并跳转到登录页面
二、创建storage,store,request
1、src目录:
注:创建storage是可选的,因为我把localstorage(缓存)封装到了storage.js(本文后续代码均是用自己封装的js);创建store是必须的!
2、创建storage(可选)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
// 封装操作localstorage本地存储的方法 模块化
var storage = {
set(key, value) {
localstorage.setitem(key, json.stringify(value));
// localstorage.key = value;
// localstorage[key] = value;
},
get(key) {
return json.parse(localstorage.getitem(key));
},
getforindex(index) {
return localstorage.key(index);
},
getkeys(){
let items = this .getall();
let keys = [];
for (let index=0;index<items.length;index++){
keys.push(items[index].key);
}
return keys;
},
getlength() {
return localstorage.length;
},
getsupport() {
return ( typeof (storage) !== "undefined" ) ? true : false ;
},
remove(key) {
localstorage.removeitem(key);
},
removeall() {
localstorage.clear();
},
getall() {
let len = localstorage.length; // 获取长度
let arr = new array(); // 定义数据集
for ( var i = 0; i < len; i++) {
// 获取key 索引从0开始
var getkey = localstorage.key(i);
// 获取key对应的值
var getval = localstorage.getitem(getkey);
// 放进数组
arr[i] = {
'key' : getkey,
'val' : getval,
}
}
return arr;
}
}
export default storage;
|
3、创建store
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import vue from 'vue'
import vuex from 'vuex'
import storage from '@/model/storage'
vue.use(vuex);
// 用vuex.store对象用来记录token
const store = new vuex.store({
state: {
// 存储token
// token: storage.get('token') ? storage.get('token') : '',
token: "" ,
username: "" // 可选
},
actions: {
// removetoken: () => {
// context.commit('set_token')
// }
},
// 计算属性
mutations: {
// 修改token,并将token存入localstorage
set_token(state,token) {
state.token = token;
storage.set( 'token' , token);
console.log( 'store、localstorage保存token成功!' );
},
del_token(state) {
state.token = "" ;
storage.remove( "token" );
},
// 可选
setuserinfo(state, username) {
state.username = username;
}
}
});
export default store;
|
4、创建request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
import axios from 'axios'
import store from '@/store'
import router from '@/router'
// create an axios instance
const service = axios.create({
// index.js设置了代理(解决跨域) invoice = http://58.246.79.142:25005
baseurl: "/invoice" , // url = base url + request url
timeout: 5000, // request timeout
}
})
//添加请求拦截器,若token存在则在请求头中加token,不存在也继续请求
service.interceptors.request.use(
config => {
// 每次发送请求之前检测都vuex存有token,那么都要放在请求头发送给服务器,没有则不带token
// authorization是必须的
if (store.state.token) {
config.headers.authorization = store.state.token;
}
return config;
},
error => {
console.log( "在request拦截器显示错误:" , error.response)
return promise.reject(error);
}
);
//respone拦截器
service.interceptors.response.use(
response => {
// 在status正确的情况下,code不正确则返回对应的错误信息(后台自定义为200是正确,并且将错误信息写在message),正确则返回响应
return response.data.code == 200 ? response : promise.reject(response.data.message);
},
error => {
// 在status不正确的情况下,判别status状态码给出对应响应
if (error.response) {
console.log( "在respone拦截器显示错误:" , error.response)
switch (error.response.status) {
case 401:
//可能是token过期,清除它
// this.$store.commit("del_token");
store.commit( "del_token" );
router.replace({ //跳转到登录页面
path: '/login' ,
// 将跳转的路由path作为参数,登录成功后跳转到该路由
query: { redirect: router.currentroute.fullpath }
});
}
}
return promise.reject(error.response.data);
}
);
export default service
|
三、配置代理,封装路由router、设置路由守卫,在main.js中引入router
一、配置代理
二、封装路由router,并设置路由守卫
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
/* eslint-disable */
import vue from 'vue'
import router from 'vue-router'
import main from '@/main/index'
import store from '@/store'
import storage from '@/model/storage'
vue.use(router)
const routes = [
{
path: '/' ,
name: 'main' ,
redirect: '/login' ,
// 某些页面规定必须登录后才能查看 ,可以在router中配置meta,将需要登录的requireauth设为true,
meta: {
requireauth: true ,
}
},
{
path: '/login' ,
component: () => import( '@/views/login' ),
},
{
path: '/invoice' ,
redirect: '/invoice' ,
component: main,
},
]
},
{
path: '*' ,
component: main
}
]
const router = new router({ routes: routes })
// 设置路由守卫,在进页面之前,判断有token,才进入页面,否则返回登录页面
if (storage.get( "token" )) {
store.commit( "set_token" , storage.get( "token" ));
}
router.beforeeach((to, from, next) => {
// 判断要去的路由有没有requiresauth
// to.matched.some(r => r.meta.requireauth) or to.meta.requiresauth
if (to.matched.some(r => r.meta.requireauth)) {
if (store.state.token) {
next(); //有token,进行request请求,后台还会验证token
} else {
next({
path: "/login" ,
// 将刚刚要去的路由path(却无权限)作为参数,方便登录成功后直接跳转到该路由,这要进一步在登陆页面判断
query: { redirect: to.fullpath }
});
}
} else {
next(); //如果无需token,那么随它去吧
}
});
export default router
|
三、在main.js中引入router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import vue from 'vue'
// import vuex from 'vuex'
import app from './app'
import router from './router'
import elementui from 'element-ui' ;
import 'element-ui/lib/theme-chalk/index.css'
// import vueresource from 'vue-resource'
// import axios from 'axios'
// 兼容ie
// import 'babel-polyfill';
vue.use(elementui);
// vue.use(vuex);
// vue.use(vueresource);
// vue.use(axios);
vue.config.productiontip = false
vue.component(collapsetransition.name, collapsetransition)
// this.$ajax 全局使用axios
// vue.prototype.$ajax=axios;
new vue({
el: '#app' ,
router:router,
components: { app },
template: '<app/>'
})
|
四、登录页面实际使用
只给出表单提交示例函数和依赖js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import { postlogin } from "@/api/login" ;
submitform(formname) {
this .$refs[formname].validate(valid => {
if (valid) {
let that = this ;
// console.log('username',this.loginform.username)
// 通过校验规则后进入校验用户名密码是否正确
postlogin( this .loginform.username, this .loginform.password)
.then(res => {
console.log(res);
that.$store.commit( "set_token" , res.data.token);
that.$store.commit( "setuserinfo" , res.data.account);
this .$notify({
title: "登录成功" ,
type: "success" ,
showclose: false ,
duration: 1000
});
settimeout(() => {
// 此时要判断/login后面的参数,若无参数,进入主页;
this .$router.push( "/index" );
// 若有参数则参数为未有权限的那个路由,跳转到那个路由
// this.$router.push(***); -- 具体要自己在这实现
}, 1000);
})
. catch (error => {
// 错误分为 status-请求错误 和 code-账号密码错误
this .$message.error(error);
console.log(error);
});
} else {
// 不符合前端校验
this .$message.error( 'format error:' +error);
console.log( 'format error:' ,error);
return false ;
}
});
}
|
上面依赖的@/api/login:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import request from '@/utils/request.js'
export function postlogin(account,password) {
console.log(account,password)
return request({
url: '/login' ,
method: 'post' ,
params:{
// 具体传参(键)要看后台要求
account:account,
password:password
}
})
}
|
以上这篇解决vue刷新页面以后丢失store的数据问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/lidongccp/article/details/90107151