解决vue刷新页面以后丢失store的数据问题

刷新页面时vue实例重新加载,store就会被重置,可以把定义刷新前把store存入本地localStorage、sessionStorage、cookie中,localStorage是永久储存,重新打开页面时会读取上一次打开的页面数据,sessionStorage是储存到关闭为止,cookie不适合存大量数据。根据我的需求,最合适的是sessionStorage。

beforeunload在页面刷新时触发,可以监听这个方法,让页面在刷新前存store到sessionStorage中。

当然,在页面刷新时还要读取sessionStorage中的数据到store中,读取和储存都写在app.vue中。

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(可选)

// 封装操作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

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

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,并设置路由守卫

/* 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

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

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:

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的数据问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • VUEX 数据持久化,刷新后重新获取的例子

    VUEX 数据持久化 // store.js getters: { userInfo(state) { console.log('getters',state); if (!state.userInfo.id) { let token = getStorage("token"); console.log('token',token); if (token) { let userInfo = getStorage("userInfo"); state.userInfo

  • vue 界面刷新数据被清除 localStorage的使用详解

    localStorage是html5新增的一个本地存储API,它有5M的大小空间,通过(key,value)的方式存储在浏览器中 window.localStorage.setItem('key', value); //储存文件 window.localStorage.getItem('key'); //读取文件 window.localStorage.removeItem('key'); //清除文件 vue中使用方法: 1.新建一个store.js文件 localStorage只能存储字符串

  • 使用sessionStorage解决vuex在页面刷新后数据被清除的问题

    1.原因 2.解决方法 localStorage没有时间期限,除非将它移除,sessionStorage即会话,当浏览器关闭时会话结束,有时间期限,具有自行百度 我这里使用sessionStorage,这里需要注意的是vuex中的变量是响应式的,而sessionStorage不是,当你改变vuex中的状态,组件会检测到改变,而sessionStorage就不会了,页面要重新刷新才可以看到改变,所以应让vuex中的状态从sessionStorage中得到,这样组件就可以响应式的变化 3.具体实现

  • vue单页应用在页面刷新时保留状态数据的方法

    在Vue单页应用中,如果在某一个具体路由的具体页面下点击刷新,那么刷新后,页面的状态信息可能就会丢失掉.这时候应该怎么处理呢?如果你也有这个疑惑,这篇文章或许能够帮助到你 一.问题 现在产品上有个需求:单页应用走到某个具体的页面,然后点击刷新后,刷新的页面要与刷新前的页面要保持一致. 这时候就需要我们保存刷新之前页面的状态. 二.一种解决方案 在这个Vue单页应用中,王二是用Vuex作为状态管理的,一开始王二的思路是将Vuex里的数据同步更新到localStorage里. 即:一改变vuex里的

  • 解决vue刷新页面以后丢失store的数据问题

    刷新页面时vue实例重新加载,store就会被重置,可以把定义刷新前把store存入本地localStorage.sessionStorage.cookie中,localStorage是永久储存,重新打开页面时会读取上一次打开的页面数据,sessionStorage是储存到关闭为止,cookie不适合存大量数据.根据我的需求,最合适的是sessionStorage. beforeunload在页面刷新时触发,可以监听这个方法,让页面在刷新前存store到sessionStorage中. 当然,在

  • 解决Vue 刷新页面导航显示高亮位置不对问题

    首先:现在是我点击在产品介绍页面 但是当我刷新页面后高亮位置就变成了第一个 在头部组件里面控制导航高亮显示是checked,默认值是0,触发点击事件会重新赋值,跳转路由,当刷新页面,checked值是0,所以要监听checked时刻发生变化:利用到vue的父子和子父传值:监听状态的变化 子页面将值传给父页面 父页面接收传过来的值 父组件把值传给header头部组件,头部组件通过prop接收 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子

  • vuex刷新页面后如何解决丢失store的数据问题

    目录 vuex刷新页面后丢失store的数据 提出问题 解决方案 vuex刷新页面数据丢失(数据持久化) 存储到localStorage中 存储到sessionStorage中 指定数据持久化 总结 vuex刷新页面后丢失store的数据 提出问题 最近遇到个问题,vue中vuex中的store数据,会在页面刷新后初始化,为了解决这一问题决定将store里面数据在页面刷新前保存到sessionStorage,至于为何用他,因为页面关闭后他会被清空,localStorage则会一直存在,cooki

  • Vue router传递参数并解决刷新页面参数丢失问题

    Vue Router 传参方式: 1. this.$router.push({ name: '模块名称', params: { // 各参数 } }) router.js: export default new Router({ routes: [ { path: '/paramsPassingByRouter', component: ParamsPassingByRouter, children: [ { path: 'paramsMode', name: 'paramsMode', com

  • 如何处理vue router 路由传参刷新页面参数丢失

    概述 常见场景:点击列表的详情,跳转到详情内页,在内页根据传递的参数获取详情数据. 路由传参一般有如下几种方式,下面主要介编程式导航 router.push 的传参方式: 方法一:通过 params 传参 路由配置如下: { path: '/detail/:id', //若id后面加?代表这个参数是可选的 name: 'detail', component: Detail } 通过 $router.push 中 path 携带参数的方式 // 列表中的传参 goDetail(row) { thi

  • vue刷新页面时去闪烁提升用户体验效果的实现方法

    首先在最外层div添加v-if="isReloadAlive",并创建变量isReloadAlive = true 随后添加provide()以及reload方法,如下: export default { provide() { return { reload: this.reload } }, data(){ isReloadAlive : true }, methods: { reload() { this.isReloadAlive = false; this.$nextTick

  • 解决vue单页面 回退页面 keeplive 缓存问题

    场景:项目中遇到 vue 点击回退 从A页跳到B页,缓存A页,当B页状态修改再次返回A时,A页查询条件缓存不刷新,列表刷新 A页: B页: 解决方法: 利用keep-alive 缓存需要缓存的页面 1.在app.vue中改写router-view <template> <div id="app"> <keep-alive> <router-view v-if="$route.meta.keepAlive"> <!

  • 解决vue单页面应用中动态修改title问题

    详细信息查看:vue-weachat-title 解决问题: 1.Vuejs 单页应用在iOS系统下部分APP的webview中 标题不能通过 document.title = xxx 的方式修改 该插件只为解决该问题而生(兼容安卓) 2.在vue单页面中,通过浏览器分享到QQ.微信等应用中的链接,只有一个首页标题和默认icon图片 已测试:APP 微信 QQ 支付宝 淘宝 安装 npm install vue-wechat-title --save 用法 1.在main.js中引入 impor

  • 解决vue单页面修改样式无法覆盖问题

    当 <style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素. vue组件编译后,会将 template 中的每个元素加入 [data-v-xxxx] 属性来确保 style scoped 仅本组件的元素而不会污染全局. 比如: <style scoped> .example { color: red; } </style> <template> <div class="example">hi<

  • 解决vue一个页面中复用同一个echarts组件的问题

    因为页面中要用echarts图表的地方比较多,所以封装了组件,方便复用,如图: 我需要这样一个饼图,并且接下来在很多次地方要用到. 直接复制官网的代码,再改改数据,需要用的时候直接拿来用. 但是接下来出现了一个问题:如果我在同一个页面多次使用这个组件,图表将不能正常显示.分析了一下, echarts通过id获取对象 // 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('main')); 当封装为

随机推荐