vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
一、安装
vue add vuex
二、起始
2.1 State
将应用全局状态定义在state中
vuex中
state: {
isLogin: false
}
2.2 Mutation
修改state只能通过mutation
vuex中
mutations: {
login(state) {
state.isLogin = true
},
logout(state) {
state.isLogin = false
}
},
2.3 获取和修改状态
使用store.state获取状态
Login.vue中
<button @click="login" v-if="!$store.state.isLogin">登录</button>
<button @click="logout" v-else>登出</button>
修改状态只能通过store.dispatch(mutation)
Login.vue中
this.$store.commit('login')
this.$store.commit('logout')
2.4 Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作
vuex中
actions: {
//参数1是vuex传递的上下文context:{commit,dispatch,state}
login({
commit }, username) {
//模拟登录api调用,1s钟以后如果用户名是admin则登陆成功
return new Promise((resolve, reject) => {
setTimeout(() => {
if (username == "admin") {
commit("login");
resolve();
} else {
reject();
}
}, 1000);
});
},
},
派发动作
Login.vue中
this.$store.dispatch('login', 'admin').then(() => {
this.$router.push(this.$route.query.redirect)
}).catch(() => {
alert('用户名或密码错误')
})
三、最佳实践
3.1 模块化
使用modules定义多个子模块利于组件复杂状态
store/index.js中
import user from './user'
export default new Vuex.Store({
modules: {
user, }
})
移动先前登录状态相关代码到user.js
store/user.js
export default {
namespaced: true, // 避免命名冲突 //
...
}
访问方式响应变化
Login.vue中
<button @click="login" v-if="!$store.state.user.isLogin">登录</button>
Login.vue中
this.$store.dispatch('user/login', 'admin').then(() => {
this.$router.push(this.$route.query.redirect);
}).catch(() => {
alert('用户名或密码错误')
})
router/index.js中
store.state.user.isLogin
3.2 mapState() / mapMutation() / mapAction()
通过这些映射方法可以让大家少敲几个字,避免对$store直接访问。
state相关修改
Login.vue
Login.vue中
import {
mapState } from 'vuex'
computed: {
...mapState('user', ['isLogin'])
}
Login.vue中
<button @click="login" v-if="!isLogin">登录</button>
action相关修改
Login.vue中
import {
mapActions } from 'vuex'
methods: {
...mapActions(['user/login', 'user/logout'])
login() {
this['user/login']('admin').then(...)
},
},
3.3 Getter
可以使用getters
从store的state
中派生
出一些状态
store/user.js中
export default {
namespaced: true, //设置独立命名空间,避免命名冲突
state: {
isLogin: false,
username:""
},
mutations: {
login(state,username) {
state.isLogin = true;
state.username = username;
},
logout(state) {
state.isLogin = false;
state.username = "";
},
},
getters:{
welcome : (state) => {
return state.username + ",欢迎回来"
}
},
actions: {
//参数1是vuex传递的上下文context:{commit,dispatch,state}
login({
commit }, username) {
//模拟登录api调用,1s钟以后如果用户名是admin则登陆成功
return new Promise((resolve, reject) => {
setTimeout(() => {
if (username == "admin") {
commit("login",username);
resolve();
} else {
reject();
}
}, 1000);
});
},
},
};
getters的使用
<span v-if="isLogin">
{
{welcome}}
<button>注销</button>
</span>
App.vue中
import {
mapState,mapGetters} from "vuex";
export default {
computed: {
...mapGetters('user',["welcome"]),
...mapState('user',["isLogin"])
},
}
四、严格模式
严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。开启严格模式 strict: true
const store = new Vuex.Store({
// ...
strict: true
})
五、插件
Vuex 的 store 接受 plugins 选项,这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接收 store 作为唯一参数:
const myPlugin = store => {
// 当 store 初始化后调用
store.subscribe((mutation, state) => {
// 每次 mutation 之后调用
// mutation 的格式为 { type, payload }
})
}
然后像这样使用:
const store = new Vuex.Store({
// ...
plugins: [myPlugin]
})
范例:实现登录状态持久化,store/plugins/persist.js
export default (store) => {
//1.store初始化的时候,将存储在 localStorage 中的状态还原
if (localStorage) {
const user = JSON.parse(localStorage.getItem("user"));
if (user) {
store.commit("user/login", user.username);//login的mutations方法
}
}
//2.如果用户相关状态发生变化,自动存入 localStorage
//监听,订阅所有的 mutation
store.subscribe((mutation, state) => {
//mutation.type
//{type:'user/login'}
//{type:'user/logout'}
//{type:'cart/addCart'}
if (mutation.type === "user/login") {
const user = JSON.stringify(state.user);
localStorage.setItem("user", user);
} else if (mutation.type === "user/logout") {
localStorage.removeItem("user");
}
});
};
store/index.js中
import Vue from "vue";
import Vuex from "vuex";
import user from "./user";
import persist from './plugins/persist'
Vue.use(Vuex);
export default new Vuex.Store({
strict: true,
modules: {
user,
},
plugins:[persist]
});
//页面一刷新,登录状态就变成false
//数据持久化
//插件