Vuex相关(长期更新)

一、vue-cli使用

1.基本配置

(1)安装node

官网下载node:https://nodejs.org/zh-cn/download/

node -V #node版本
npm -V #npm版本

(2)安装vue和vue-cli

npm install vue
npm install --global vue-cli

(3)创建基于webpack的项目

vue init webpack vue-study #初始化
cd vue-study #进入项目文件夹

1b9632772e70b22ffe9b9552ca3e5e8ab93.jpg

项目创建好

(4)运行项目

npm run dev

2c209b3c438f115d3d63d8b5b4522397e6b.jpg

项目运行成功

2.增加一些配置

(1)eslint报错修复

abec0c56607a2307caaf51d601b03385f46.jpg

    "lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/",

格式错误可以通过

npm run lint-fix

(2)添加中心状态管理

安装vuex

npm i vuex -D

e609fbaf30c7e7939aa44f5dcaf88b0fcfb.jpg

新建store文件夹及其以下文件

import Vue from 'vue'
import vuex from 'vuex'
import mutations from './mutations/mutations'
import actions from './actions/actions'
import getters from './getters/getters'
import state from './state/state'
Vue.use(vuex)

export default new vuex.Store({
  state,
  getters,
  actions,
  mutations
})

store/store.js

0efe732bfc0ae819fd596c6cf20eb251476.jpg

import store from './store/store'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

引入store

A.state和getters

87b9c652eddf02e8c475549d7b91af3d8e0.jpg

state/state.js

ce7d9bc92ddb49854adf6db7d654d911bdb.jpg

getters.js

mutations.js,actions.js都是export default{}形式

67f8fa33b2754465fe2f1a93e72b3794cf5.jpg

export default {
  name: 'App',
  mounted: function () {
    this.useStore()
  },
  methods: {
    useStore () {
      console.log(this.$store.state.count) // -> 0
    }
  },
  computed: {
    fullName () {
      return this.$store.getters.fullName
    }
  }
}

App.vue

npm run dev

运行

3c48b438bbad6a86225986d038d8529f75b.jpg

打印出store里的state,得到getters里面的值

B.mutations,actions

b6a07dee6b6946e0d9940c562e71a80c371.jpg

export default {
  updateCountAsync (store, data) {
    setTimeout(() => {
      store.commit('updateCount', {
        num: data.num
      })
    }, data.time)
  }
}

actions.js

8f24049be357fdca0b97fae9f631d1ad62e.jpg

export default {
  updateCount (state, {num, num2}) {
    state.count = num
  }
}

mutations

9be909d50b2ece01007c7d0d3c3c19fbb06.jpg

452b62157a4989ed800f2dc5bc67633d415.jpg

dispatch用来触发actions,和commit用来触发mutations一样

{{this.$store.state.count}}

  mounted: function () {
    this.useStore()
    this.useMutations() // 执行后立即变成20
    this.$store.dispatch('updateCountAsync', {
      num: 5,
      time: 2000
    }) // 执行后2秒变成5
  },
  methods: {
    useStore () {
      console.log(this.$store.state.count) // -> 0
    },
    useMutations () {
      this.$store.commit('updateCount', {
        num: 20,
        num2: 2
      })
    }
  },

App.vue

npm run dev

97def4175212cc049c6e2b40e1c64d29f95.jpg

 

82496c4405ab932874fed7d7e572cd5363a.jpg

2秒之后从20变成5

C.让store使用更便捷

03d893de7b10e9b64c91455e3ac31fc683c.jpg

<script>
import {
  mapState,
  mapGetters
} from 'vuex'
export default {
  name: 'App',
  mounted: function () {
  },
  methods: {
  },
  computed: {
    ...mapState(['count']),
    ...mapGetters(['fullName'])
  }
}

d0bad93949e4d40a6a03055d9249737cf08.jpg

使用map语法更简洁获得state和getters里的值。

 

(3)跨域代理

A.axios和proxyTable解决get跨域问题

npm i axios -D #安装axios

8f122814f730570f0e5c9966d316b2e0d0d.jpg

import axios from 'axios'
Vue.prototype.$axios = axios

src/main.js全局添加axios

416883d10c0a7121871e7206f64e7f216fb.jpg

拿到一个本地数据

db5c22d63e2c65d17d03627fb66467ae72a.jpg

jsonview后的视图

8fa6482f267b938485693dc5914859c71ca.jpg

    proxyTable: {
      '/api': {
        target: 'http://localhost:8000',
        changeOrigin: true,
        pathRewrite: {
          '^/api': '/'
        }
      }
    },

config/index.js

5cb71afbf6cd72828d0f0887ae8f5d86c1e.jpg

API_HOST: '/api/'

condfig/dev.env.js增加API_HOST

db0cef0160b1cc670e51ccc58d733a94463.jpg

API_HOST: '"http:/xxx.xxx.xxx.xxx:8000"' // 生产环境的地址,上线后修改

config/prod.env.js增加线上地址接口

ae463018164e9eabbb90ecb1f2f9372ca32.jpg

  mounted: function () {
    this.getapi()
  },
  methods: {
    getapi () {
      this.$axios.get('/api/article/', {
        params: {format: 'json'}
      })
        .then((res) => {
          console.log(res)
        })
        .catch(function (error) {
          console.log(error)
        })
    }
  }

App.vue内调用,注意接口格式

npm run dev

启动开发环境

4845a3ee4df7a29b7148792bcc7ee5858d9.jpg

查看控制台输出跨域接口信息

B.qs解决post发送兼容问题

93c7e92374e578d845e08d305321aa4d911.jpg

import qs from 'qs'

Vue.prototype.$axios = axios
Vue.prototype.$qs = qs

main.js

9a8327a53707eee6e04b5d9839430d3de40.jpg

    postapi () {
      let data = this.$qs.stringify({'schools': 1, 'id': 1})
      /* 接口请求 */
      this.$axios.post('/api/userSchoolFav/', data)
        .then((res) => {
          console.log('POST数据Fav返回值:', res)
        })
        .catch(function (error) {
          console.log(error)
        })
    }

或者qs非全局注册

import Qs from 'qs'
export default {
   methods:{
    postapi () {
      let data = Qs.stringify({'schools': 1, 'id': 1})
      /* 接口请求 */
      this.$axios.post('/api/userSchoolFav/', data)
        .then((res) => {
          console.log('POST数据Fav返回值:', res)
        })
        .catch(function (error) {
          console.log(error)
        })
   }
}

当前页面引入并使用

C.解决跨域携带token信息(JWT的方式不是cookie,所以这里暂时用不上)

0db344bd83dc58f78123d2dde2b575f944b.jpg

axios.defaults.withCredentials = true // 允许跨域携带cookie信息

以jwt的token为例:

参考:https://my.oschina.net/u/3018050/blog/2054854

(4)jquery配置

安装jquery

npm install jquery -D

6e7091a38c25ca6ec40dd90eba973cfda9b.jpg

const webpack = require('webpack')

663faa7308a0f4b9b25f060408142f3ae40.jpg

  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      jquery: "jquery",
      "window.jQuery": "jquery"
    })
  ],

添加build/webpack.base.conf.js相关plugin

12e34990e79addf0af06646c1235c21db72.jpg

import 'jquery'

main.js

30cd55edc575c3d573337528a2c7955361f.jpg

    jquery: true// 添加

f4d7eafab70d46da1f90e3aa24a5bf2acb7.jpg

96b850747bc3ab8aef2f92264675d3792d6.jpg

961fc3e83476509e70552f5e5203087903b.jpg

可以获得到,jquery可以使用

(7)styl使用

安装styl-loader

npm install stylus stylus-loader -D

57fca8604036b1f8877665f911f5e4e0248.jpg

<style scoped lang="stylus">

语言上lang='stylus'即可

60e3bdba8c6977cff94e2a73a175c326259.jpg

e406eab072bf7342b2b6ca5c0036fad98f3.jpg

287552b7348f6d68569b68a9e112279d117.jpg

<style lang="stylus">
@import "assets/base.styl"

25061c02d587ddd3a099d4e593a11d61c9e.jpg

外部引用

(5)外部ui库

以element UI为例

安装element ui

npm i element-ui -S #安装element-ui
npm i sass-loader node-sass -D #安装sass-loader,node-sass

7a649292b3c836e96b0403bba30fa3ffe40.jpg

/* 改变主题色变量 */
$--color-primary: teal;

/* 改变 icon 字体路径变量,必需 */
$--font-path: '../../node_modules/element-ui/lib/theme-chalk/fonts';
@import "../../node_modules/element-ui/packages/theme-chalk/src/index";

新建src/assets/element-variables.scss文件

17a891b45c0993045f27148671a053cd4f4.jpg

import Element from 'element-ui'
import './assets/element-variables.scss'
Vue.use(Element)

b30f3cc61efdd6867a4937043bf2b71cd2b.jpg

使用element ui

b286e29028fa04fab09ab6008184a574a7a.jpg

主要按钮的主题色定义好

 

3.优化一些设置

(1)使用路由守卫和request/response 拦截器

4f5a0046c8568fdc3fadf9bec9ea9cb9363.jpg

在main.js里添加每个跳转前的路由钩子。这里是通过JWTtoken是否存在,以及跳转页面是否为登录页、注册页、或者个人中心(例如个人信息页面)等,确定对localstorage里存储的token是否进行删除,以及是否需要跳转回登录页面

d9605c9c2449bb69674cedffbe46d471048.jpg

对request拦截,判断localstorage里的token是否存在,来添加authorization认证信息,确保登录成功的状态下,每次发送信息携带JWTtoken,使得一些需要用户权限的页面能够顺利通过

01f8e72f03a05bbf1d6f70c83fa11742ffe.jpg

59945d2f2b1a4ad39ea88be755df60d1979.jpg

对response拦截,判断返回信息中是否有用户未登录401,或者登录认证错误403的情况,如果有,则返回登录页面

这里对路由钩子和http拦截判断打印数字,以便在控制台更好看到操作时,走的逻辑路径

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'

import App from './App'
import router from './router'
import store from './store/store'
import axios from 'axios'
import qs from 'qs'
// import 'jquery'
import Element from 'element-ui'
import './assets/element-variables.scss'

import IndexHeader from '@/layout/Header'
import IndexFooter from '@/layout/Footer'
import Banner from '@/components/Banner'
import Pages from '@/components/Pages'

Vue.use(Element)

Vue.component('IndexHeader', IndexHeader)
Vue.component('IndexFooter', IndexFooter)
Vue.component('Banner', Banner)
Vue.component('Pages', Pages)

router.beforeEach(({name}, from, next) => {
  // 获取 JWT Token
  if (localStorage.getItem('JWT_TOKEN')) {
    // JWT_TOKEN存在
    console.log(1)
    if (name === 'login' || name === 'register') {
      // 登录按钮点击,清楚JWT Token
      store.commit('DELSTORELOG')
      console.log(2)
      next()
    } else {
      // 其他页面返回
      console.log(3)
      next()
    }
  } else {
    // JWT_TOKEN不存在
    console.log(4)
    if (name === 'Information') {
      // 查看个人信息页面
      console.log(5)
      next({name: 'login'})
    } else {
      console.log(6)
      next()
    }
  }
})

// http request 拦截器
axios.interceptors.request.use(
  config => {
    if (localStorage.JWT_TOKEN) { // 判断是否存在token,如果存在的话,则每个http header都加上token
      console.log(7)
      config.headers.Authorization = `JWT ${localStorage.JWT_TOKEN}`
      console.log('存在', localStorage.JWT_TOKEN)
    } else {
      console.log('不存在')
    }
    return config
  },
  err => {
    console.log(8)
    return Promise.reject(err)
  })

// http response 拦截器
axios.interceptors.response.use(
  response => {
    console.log(9)
    return response
  },
  error => {
    console.log(10)
    if (error.response) {
      console.log(11)
      console.log('axios:' + error.response.status)
      switch (error.response.status) {
        case 401:
          // 返回 401 清除token信息并跳转到登录页面
          store.commit('DELSTORELOG')
          router.replace({
            path: 'login',
            query: {redirect: router.currentRoute.fullPath}
          })
          break
        case 403:
          // 返回 403 清除token信息并跳转到登录页面
          store.commit('DELSTORELOG')
          router.replace({
            path: 'login',
            query: {redirect: router.currentRoute.fullPath}
          })
          break
      }
    }
    return Promise.reject(error.response.data) // 返回接口返回的错误信息
  })
Vue.prototype.$axios = axios
Vue.prototype.$qs = qs
axios.defaults.withCredentials = true // 允许跨域携带cookie信息(例如session等),使用localstorage设置为false
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

main.js

(2)mutations-types.js的设置

A.设置前

e2a7e2f1d3ebf1ae8c2f6aa1425fb128b7c.jpg

  SETUSERINFO (state, info) {
    state.userInfo = info
  }

8131daea222aa09bacb504e4bd69aa5de8a.jpg

b77d6270802ccfc5d8f1da3194c97869578.jpg

2d8c7f2972659eb9cd13641a57d7fabd395.jpg

this['SETSTORELOG'](res.data.token)
B.设置后

8d1825fec9162570c72ed9bdf115f276fc0.jpg

import {
  SETUSERINFO
} from '../mutation-types.js'
export default {
  [SETUSERINFO] (state, info) {
    state.userInfo = info
  }
}

0cb8c3c237bb75bbe576ac190abcf47e017.jpg

新建store/mutation-types.js

a0c25eb1ba9f154bdde7e8907cf910e915b.jpg

af4a6c96d452e33536e49db684af2edd09d.jpg

0f7ce3605398921f99944ca5c09fccbd823.jpg

this.SETSTORELOG(res.data.token)
对比

1)增加mutation-types.js后,需要在mutations.js里引入,并且将所有方法名用[]括起来。

2)两者引入都徐亚用map from vuex的方式,并且在methods里添加该方法

3)使用时,无mutation-types需要将方法名用[]括起来,而有mutation-types时,则直接使用,不需要[]

(3)封装axios方法

A.封装思路

7a222b1dbbfb5f827e36e1ad81d1aeac620.jpg

import axios from 'axios'
export default {
  ajaxGet (api, cb) {
    axios.get(api).then(cb).catch(err => { console.log(err) })
  },
  ajaxPost (api, post, cb) {
    axios.post(api, post).then(cb).catch(err => { console.log(err) })
  }
}

新建src/axios/http.js

9af60996126d36a6fd5804ae01a4500ab3d.jpg

6bc2d5969624ba22e833065718ce34c1ed6.jpg

import http from './axios/http'
Vue.prototype.$http = http

在main.js中引入

77d056756cc274fce9c73df11a5d69d534a.jpg

<template>
  <div id="app">
    <IndexHeader></IndexHeader>
    <div @click="GetMethod">axios封装get方法</div>
    <div @click="PostMethod">axios封装post方法</div>
    <router-view/>
    <IndexFooter></IndexFooter>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods: {
    GetMethod () {
      this.$http.ajaxGet('/api/article/', res => {
        console.log('ajaxGet', res)
      })
    },
    PostMethod () {
      this.$http.ajaxPost('/api/userSchoolFav/', {'schools': 1}, res => {
        console.log('ajaxPost', res)
      })
    }
  }
}
</script>

在.vue文件中使用

b81664d7a0dbb61c042b7ebf1def1ee363a.jpg

点击后可在控制台看到相关内容。

这种封装方式更简化了写法,不需要then,catch这些关键字,专心写里面的处理逻辑

由此,我们可以将一些常用方法封装起来

B.一些方法封装示例

ed6e418943039f683a2130473bb3627cf02.jpg

新建src/axios/methods.js来保存常用方法,方便在调用

import axios from 'axios'
export default {
  ajaxGetArticle (api) {
    axios.get(api).then((res) => {
      console.log('ajaxGetArticle', res)
    }).catch(err => { console.log(err) })
  },
  ajaxPostUserSchoolFav (api, post) {
    axios.post(api, post).then((res) => {
      console.log('ajaxPostUserSchoolFav', res)
    }).catch(err => { console.log(err) })
  }
}

bdda78ffe1bf8848c056451561c79706a7d.jpg

<template>
  <div id="app">
    <IndexHeader></IndexHeader>
    <div @click="GetMethod">axios封装get方法method</div>
    <div @click="PostMethod">axios封装post方法method</div>
    <router-view/>
    <IndexFooter></IndexFooter>
  </div>
</template>

<script>
import http from './axios/methods.js'
export default {
  name: 'App',
  methods: {
    GetMethod () {
      http.ajaxGetArticle('/api/article/')
    },
    PostMethod () {
      http.ajaxPostUserSchoolFav('/api/userSchoolFav/', {'schools': 2})
    }
  }
}
</script>

.vue里引用方法并使用

25a7b0667c91a1e679e7f34e33e13281460.jpg

可以看到页面能够调用。

目的和使用:

这种方式在rest模式下,当数据格式和返回status一致时,提供很好的使用方法。

比如,我们要调用很多列表数据时,写了很多不同的.vue下模板,填充数据,就可以用一条流水线的方式来处理。

把axios发送get请求,对获得列表统一置入当前this的data下,这样的方式封装好。

然后统一在method里使用这个方法带上url参数即可。

当然,填写表单也是这个思路,只是多个post传递数据对象,表单还要对返回的错误提示进行提醒,也就是error里操作显示给用户看。前面我们都是把method方法和error打印进行统一处理,现在可以针对不同的error代码独立出来不再封装即可灵活使用

举例:

e9d9ec5cbf84b2d82474a7166400cc2c42f.jpg

import axios from 'axios'
export default {
  ajaxgetList (api, that) {
    axios.get(api).then((res) => {
      console.log(res.data.results)
      if (res.status === 200) {
        that.list = res.data.results
        that.allCount = res.data.count
      } else {
        that.$message.error('获取失败')
      }
    }).catch(err => { console.log('cuole', err) })
  }
}

axios/methods.js,写入方法,传入that指代this

87a1820a85c073f7dc59ff62949c1e85294.jpg

schoolList局部引入

51f01fa6631f09ed1aa8dfa9400405506a3.jpg

schoolList一行代码调用

10acf153d6ca7efd0525b17a9293b53219d.jpg

同理,teacherList局部引入

3a092c7727b0478fb536859fec5e99b14f2.jpg

同理,teacherList一行代码调用

如此即可方便使用。

f24f6ae66c0320b1cb03925c9a7ca723fe1.jpg

import axios from 'axios'
export function ajaxgetList2 (api, that) {
  axios.get(api).then((res) => {
    console.log(res.data.results)
    if (res.status === 200) {
      that.list = res.data.results
      that.allCount = res.data.count
    } else {
      that.$message.error('获取失败')
    }
  }).catch(err => { console.log(err) })
}

如果只是一个方法单独在一个文件里,可以导出为命名方法

77fbdf26e41868b5ee960627849a5a6974e.jpg

两种引用方法都可

07793b16c0c7089a017c1d6e4970de8a094.jpg

使用不需要http下了

 

 

(4)actions提交mutation(未练习)

import * as types from './mutation-types';
// 提交mutation
function makeAction (type) {
  return ({ commit }, ...args) => commit(type, ...args);
};
export const setShopList = makeAction(types.SET_SHOPLIST);

actions.js

import * as types from './mutation-types';
import cookie from '../static/js/cookie';
import {getShopCarts} from '../api/api'
// 类似于事件 每个mutation都有字符类型的事件类型和回调函数
//全局引入vue
import Vue from 'vue';
import Axios from 'axios';
Vue.prototype.$http = Axios


export default {
    [types.SET_SHOPLIST] (state) { //设置购物车数据
        // token = cookie.getCookie('token')
        if(cookie.getCookie('token') != null){
          getShopCarts().then((response)=> {
            // 更新store数据
            state.goods_list.goods_list = response.data;
            console.log(response.data)
            var totalPrice = 0
            response.data.forEach(function(entry) {
              totalPrice += entry.goods.shop_price*entry.nums
            });
            state.goods_list.totalPrice = totalPrice;

          }).catch(function (error) {
            console.log(error);
          });
        }
    },


}

mutations.js

// 获取购物车数据
export const SET_SHOPLIST = 'SET_SHOPLIST';

mutation-types.js

        addShoppingCart () { //加入购物车
            addShopCart({
                goods: this.productId, // 商品id
                nums: this.buyNum, // 购买数量
            }).then((response)=> {
                this.$refs.model.setShow();
                // 更新store数据
                this.$store.dispatch('setShopList');

            }).catch(function (error) {
                console.log(error);
            });
        },

.vue中method方法使用

C.http拦截器抽出

e0a349cb1a6522daa0a8911ee6cba7c69a3.jpg

import {getStore} from '../util/mUtils'
import axios from 'axios'
// 全局状态控制引入
import store from '../store/store'
import router from '../router'

// http request 拦截器
axios.interceptors.request.use(
  config => {
    if (localStorage.JWT_TOKEN) { // 判断是否存在token,如果存在的话,则每个http header都加上token
      // 1.不设置有效期
      // config.headers.Authorization = `JWT ${localStorage.JWT_TOKEN}`
      // 2.设置有效期
      let JWT_TOKEN = getStore('JWT_TOKEN')
      config.headers.Authorization = `JWT ${JWT_TOKEN}`
    } else {
    }
    return config
  },
  err => {
    return Promise.reject(err)
  })

// http response 拦截器
axios.interceptors.response.use(
  response => {
    return response
  },
  error => {
    if (error.response) {
      console.log('axios:' + error.response.status)
      switch (error.response.status) {
        case 401:
          // 返回 401 清除token信息并跳转到登录页面
          store.commit('DELTOKEN')
          router.replace({
            path: 'login',
            query: {redirect: router.currentRoute.fullPath}
          })
          break
        case 500:
          console.log('服务器错误')
        // case 403:
        //   // 返回 403 清除token信息并跳转到登录页面
        //   store.commit('DELTOKEN')
        //   router.replace({
        //     path: 'login',
        //     query: {redirect: router.currentRoute.fullPath}
        //   })
        //   break
      }
    }
    return Promise.reject(error.response.data) // 返回接口返回的错误信息
  })

新建src/axios/index.js,把main.js中关于http拦截器部分全部剪切过来

4c0d74796f419e5be1d6e290150fef5354b.jpg

在main.js中引入

(5)设置default/404图片

对图片src是否存在,404等情况设置默认图

<!-- 404Img -->
<template>
  <div style="width:100%;height:500px;border:2px solid red">
    <img :src="avatar?avatar:defaultNoImage" :onerror="defaultImg" alt="" >
  </div>
</template>

<script>
export default {
  name: 'Demo404Img',
  data () {
    return {
      defaultImg: 'this.src="' + require('../assets/images/banner1.jpg') + '"',
      defaultNoImage: 'this.src="' + require('../assets/images/banner2.jpg') + '"',
      avatar: '../static/images/avatar-1.jpg'
    }
  }
}
</script>

 

 

 

报错解决

1.[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

4841b541be82f3b306a1c73c6ebd9a97e29.jpg

  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.js'
    }
  }

2.npm install时,报错:正在生成解决方案配置“Release|x64”。

9a66bb57e205e1257437981ac8b84ebf550.jpg

npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/

设置全局镜像源,之后再涉及到 node-sass 的安装时就会从淘宝镜像下载。

3.服务器http://localhost:8080要求用户输入用户名和密码

dc3dec8a4e3ace1d6f55698cbd10e8d8735.jpg

还未解决

 

 

 

参看文档

1.vuex官方中文文档:https://vuex.vuejs.org/zh-cn/

2.详解 Vue & Vuex 实践:https://zhuanlan.zhihu.com/p/25042521

3.运用JS设置cookie、读取cookie、删除cookie:https://www.cnblogs.com/limeiky/p/6927305.html

4.Django框架基于session的登录/注销实现:https://www.cnblogs.com/cllovewxq/p/7878248.html

5.前后端分离之JWT(JSON Web Token)的使用:https://segmentfault.com/a/1190000010444825

6.Vue 中使用 jQuery:https://blog.youkuaiyun.com/anxin_wang/article/details/78788773

7.在vue项目中使用stylus:https://blog.youkuaiyun.com/shooke/article/details/75907388

8.Vue的elementUI实现自定义主题:https://blog.youkuaiyun.com/wangcuiling_123/article/details/78513245

9.【Vue】axios请求的方法封装和运用:https://blog.youkuaiyun.com/lgysjfs/article/details/80407130

10.node-sass 安装失败的解决办法:https://lzw.me/a/node-sass-install-helper.html#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%E4%B8%80%EF%BC%9A%E4%BD%BF%E7%94%A8%E6%B7%98%E5%AE%9D%E9%95%9C%E5%83%8F%E6%BA%90

11.vue 显示图片404的解决办法:https://blog.youkuaiyun.com/qq_15576765/article/details/83823700

转载于:https://my.oschina.net/u/3018050/blog/1810212

### Vuex 中实现页面缓存的核心方法 在 Vue.js 的开发过程中,使用 Vuex 来管理页面状态并实现缓存是一种常见的需求。以下是基于提供的引用内容以及专业知识总结的具体实现方式。 #### 1. 使用 `keep-alive` 和 `vuex` 配合实现页面缓存 为了实现页面缓存功能,可以通过在全局的 `App.vue` 文件中包裹 `<keep-alive>` 组件来控制哪些页面会被缓存[^1]。具体来说,`<keep-alive>` 可以接收一个名为 `include` 或 `exclude` 的属性,用于指定需要被缓存或排除缓存的组件名称。这些组件名通常可以从 Vuex 的状态中动态读取。 ```vue <template> <div id="app"> <keep-alive :include="cachedPages"> <router-view /> </keep-alive> </div> </template> <script> export default { computed: { cachedPages() { return this.$store.state.keepAlives; // 动态获取需要缓存的页面列表 } } }; </script> ``` 上述代码片段展示了如何通过 Vuex 状态中的 `keepAlives` 数组动态决定哪些页面应该被缓存。 --- #### 2. 利用 `vuex-persistedstate` 插件持久化 Vuex 数据 如果希望 Vuex 的状态能够在浏览器刷新后仍然保留,则可以引入第三方插件 `vuex-persistedstate`[^2]。该插件能够将 Vuex 的状态保存至本地存储(如 localStorage),从而实现在不同会话之间的数据共享。 ```javascript import Vuex from 'vuex'; import createPersistedState from 'vuex-persistedstate'; const store = new Vuex.Store({ state: { keepAlives: [] // 存储需要缓存的页面名称 }, mutations: { updateKeepAlives(state, pages) { state.keepAlives = pages; } }, plugins: [ createPersistedState({ storage: window.sessionStorage }) // 将状态保存到 sessionStorage ] }); ``` 以上代码实现了对 `keepAlives` 状态的持久化处理,确保即使用户关闭再打开网页,缓存设置依然有效。 --- #### 3. 结合路由元信息 (`meta`) 控制缓存逻辑 对于更复杂的场景,比如某些特定条件下才允许缓存某个页面,可以在路由配置中加入自定义的 `meta` 属性,并结合导航守卫完成判断和操作[^5]。 ```javascript // 路由配置示例 { path: '/music-list', name: 'MusicList', component: () => import('@/views/MusicList'), meta: { cacheable: true } // 是否支持缓存 } ``` 接着,在全局前置守卫中根据当前路由的 `meta.cacheable` 值更新 Vuex 的 `keepAlives`: ```javascript router.beforeEach((to, from, next) => { const isCacheable = to.meta && to.meta.cacheable; if (isCacheable) { store.commit('updateKeepAlives', [...new Set([...store.state.keepAlives, to.name])]); } next(); }); ``` 此部分代码说明了如何依据路由的元信息动态调整 Vuex 中维护的缓存页面集合。 --- #### 4. 清理不需要的缓存数据 当离开某页面或者切换条件变化时,可能需要清除对应的缓存记录。这同样可通过监听路由的变化事件达成目标。 ```javascript watch: { $route(to, from) { if (!to.meta || !to.meta.cacheable) { this.$store.commit('updateKeepAlives', this.$store.state.keepAlives.filter(name => name !== from.name)); } } } ``` 这里展示了一个简单的例子:一旦检测到新访问的目标路径不满足缓存条件,则移除之前路径的相关条目。 --- ### 总结 综上所述,借助于 `keep-alive` 提供的基础能力,配合 Vuex 对全局状态的有效管控,再加上辅助工具如 `vuex-persistedstate` 执行长期储存任务,最终构建起一套完整的前端页面级缓存解决方案[^1][^3][^4][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值