vuex作用
多个页面都需要用到的数据,你可以使用vuex来存储。
如何使用?
首先需要安装vuex
cnpm i vuex
然后在项目的src目录下创建一个store的文件夹,接着创建一个number.js,该文件用于存储数字。这个数字各个页面都需要用到。然后编写以下代码 :
const state = {
number : 100
};
export default{
state
}
vuex规定,公共的数据用一个变量名叫state的对象存储,需要注意的是这个变量的名字不能改成别的。
然后在store文件夹下创建一个index.js,编写以下代码 :
import Vue from 'vue'
import Vuex from 'vuex';
import NumberManager from './number';
Vue.use(Vuex);
export default new Vuex.Store(NumberManager);
最后把vuex注入到vue中即可。打开main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store' //这里!!!
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store, //这里!!!
components: { App },
template: '<App/>'
})
准备工作都完成了,现在你可以在各个页面中,使用
this.$store.state.变量名
来访问公共数据。比如我想在某个页面中访问number,则 :
this.$store.state.number
mutations
vuex除了可以读取公共数据外,当然也可以设置公共数据。比如上面的例子,我想把number的值改成101,则需要用到一个叫"mutations "的东东。如 :
const state = {
number : 100
};
const mutations = {
setNumber(state,number){
state.number = number;
}
}
export default{
state,
mutations //注意这里需要导出
}
mutations下的setNumber是函数名,随便一个名字都可以。函数有2个参数,第一个参数是state对象,就是我们上面定义的
const state = {
number : 100
};
第二个参数是一个值,用来修改number。然后我们就可以使用vuex提供的commit方法来修改number的值了。如下 :
this.$store.commit('setNumber',101);
commit的第一个参数是mutations下定义的函数名,第二个是修改的值。
说到这里,或许你会问为什么我们都可以以
this.$store.state.number
这样的方式来访问到number的值了,我们直接修改不可以吗?比如这样 :
this.$store.state.number = 101;
直接修改确实可以,但是不推荐这样做,后面会说这个原因。
getter
访问vuex中的某个变量,我们都需要写一大串this.$store.state.xxx,此时使用getter可以简化这不操作。在number.js中增加以下代码 :
const state = {
number : 100
};
const getters = {
getNumber : (state)=>{
return state.number;
}
}
const mutations = {
setNumber(state,number){
state.number = number;
}
}
export default{
state,
getters, //注意导出
mutations
}
然后在使用的组件页面上,需要引入mapGetters,如下 :
import { mapGetters } from 'vuex';
然后在computed下定义函数名
computed : {
...mapGetters([
'getNumber ',
])
}
这样我们就可以直接访问通过getNumber来访问number的值了。如下 :
<template>
<div class="hello">
{{getNumber}} //直接访问vuex中,number的值
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed : {
...mapGetters([
'getNumber ',
])
},
created(){
console.log(this.getNumber); //直接访问vuex中,number的值
}
}
</script>
<style scoped>
</style>
actions
vuex里,除了state、getters、mutations,还提供了一个叫actions的东西。它是用来执行异步操作的,但最后也是修改state里的数据。
例子 :
比如现在公共数据里,我想把用户的登录信息也保存在vuex中,用户信息需要请求某个接口来获取,这个请求的代码就可以放在actions中。
先在number.js中增加以下代码 :
const state = {
number : 100,
userMsg : '',
};
const getters = {
getNumber : (state)=>{
return state.number;
}
}
const actions = { //新增
getUserMsg({commit}){
let str = {
name : 'tom',
level : 'vip8'
}
commit('setUserMsg', str);
}
}
const mutations = {
setNumber(state,number){
state.number = number;
},
setUserMsg(state,str){ //新增
state.userMsg = str;
}
}
export default{
state,
getters,
actions, //注意导出
mutations
}
actions里的变量str,这里由于没有接口,我们暂时把str的值当做是请求某个接口得来的。正常的写法大概是这样的 :
const actions = {
async getUserMsg({commit}){
let str = '';
let res = await axios({
method: 'post',
url: '/api/getUserMsg',
data: {
type : 'getUserMsg',
}});
if(res.returnCode == 200){
str = res.data.userMsg;
commit('setUserMsg', str);
}
}
}
然后如果在某个页面中,我们需要获得用户的信息,我们可以执行以下代码 :
this.$store.dispatch('getUserMsg');
执行这句后,vue会去检查vuex里的actions有没有getUserMsg这个方法,有的话就会执行,最后还是调用commit,执行mutations里的方法,把用户信息保存在state里。
models
上面的actions例子中,我们在state的变量里,存放了一个叫userMsg的变量,但仔细想想,这个number.js只是用来存储数字的,这时候把用户信息存储在number.js里,是否不太合适?此时我们可以使用vuex提供的models属性。具体步骤如下 :
1、把number.js里,userMsg的相关数据提取出来,再写一个js脚本。如下 :
user.js
const state = {
userMsg : '',
};
const actions = {
getUserMsg({commit}){
let str = {
name : 'tom',
level : 'vip8'
}
commit('setUserMsg', str);
}
}
const mutations = {
setUserMsg(state,str){
state.userMsg = str;
}
}
export default{
state,
actions,
mutations
}
写法和number.js一模一样。
2、修改store文件夹下的index.js
import Vue from 'vue'
import Vuex from 'vuex';
import NumberManager from './number';
import UserManger from './user';
Vue.use(Vuex);
export default new Vuex.Store({
modules : {
NumberManager,
UserManger
}
});
这样既可。
需要注意的是,如果使用了modules,此时我们访问vuex中的这个number,就不能这样写了
this.$store.state.number
因为此时的state有2个,一个是number.js的,一个是user.js的,正确的写法如下 :
this.$store.state.NumberManager.number
NumberManager是在index.js里import时,定义的名字。这样写代码貌似更长了,所以我们可以使用上面说到的,使用getters来获取vuex中的变量
plugins
现在我们把number的值改成101,但是如果此时把
this.$store.commit('setNumber',101);
这段代码注释掉,在刷新浏览器发现,number的值还是100。此时我们可以使用vuex提供的plugins插件功能。步骤如下 :
1、新建一个js,名字随意。这里我取名叫saveInLocal.js,然后在这个js里编写以下代码 :
export default store => {
if (localStorage.state) {
store.replaceState(JSON.parse(localStorage.state));
}
store.subscribe((mutation, state) => {
localStorage.state = JSON.stringify(state);
})
}
如果看不懂es6的写法,可以参考下面的代码,功能是一样的
export default function(store){
if (localStorage.state){
store.replaceState(JSON.parse(localStorage.state));
}
store.subscribe(function(mutation, state) {
localStorage.state = JSON.stringify(state);
});
}
2、修改index.js
import Vue from 'vue'
import Vuex from 'vuex';
import NumberManager from './number';
import UserManger from './user';
import saveInLocal from './saveInLocal '; //这里!!!
Vue.use(Vuex);
export default new Vuex.Store({
modules : {
NumberManager,
UserManger
},
plugins : [saveInLocal] //这里!!!
});
好了,此时只要修改vuex中的数据,再刷新浏览器数据还是没有丢失。原因是我们配置了plugins。只要配置了这个插件,那项目
运行的第一次就会去执行plugins规定好的函数。该函数只有一个返回值,那就是store。这里的store和我们在页面内,
使用的this.$store是同一个东西。
先来分析下这几句代码 :
if (localStorage.state){
store.replaceState(JSON.parse(localStorage.state));
}
localStorage.state是一个自定义属性,localStorage的自定义属性都会保存在浏览器中,比如 :
然后在来看下面这句代码 :
store.subscribe(function(mutation, state) {
localStorage.state = JSON.stringify(state);
});
这句代码相当于一个注册监听函数,当我们使用this.$store.commit来修改vuex中的数据时,修改完毕后会调用subscribe这个方法, 该方法返回的state就是vuex中所有的state。比如我们例子中的number.js和user.js中的state
然后我们把它转换成字符串,存储在localStorage.state中。所以一开始的这句代码
if (localStorage.state){
store.replaceState(JSON.parse(localStorage.state));
}
就是判断localStorage.state有没有值,如果有则取出来转换成json格式,并且调用store的replaceState方法覆盖所有state。这也
是为什么我们不要直接修改state的值的原因