Vuex
Vuex
为vue.js应用程序开发的状态管理模式
采用集中式存储管理应用的所有组件状态
以相应的规则保证以一种可预测的方式发生变化
应用场景
读取,多个视图依赖于同一个状态
修改,不同视图的行为需要改变同一个状态
组成部分
State 数据仓库
getter 获取数据
Mutation 修改数据
Action 提交mutation
安装Vuex
1、安装vuex包:npm install vuex
2、创建实例:new Vuex.store()
3、在main.js中将vuex实例挂载到vue对象上
import Vue from 'vue' import App from './App.vue' import Vuex from 'vuex' Vue.config.productionTip = false Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 } }) new Vue({ store, render: h => h(App), }).$mount('#app')
count++示例
思路
1、state中创建count字段
2、mutations中创建一个count++的mutation
3、button新增click事件触发mutation改变count
main.js
import Vue from 'vue' import App from './App.vue' import Vuex from 'vuex' Vue.config.productionTip = false Vue.use(Vuex) const store = new Vuex.Store({ // 状态数据 state: { count: 0 }, // 状态改变方法 mutations: { // 第一个参数是state, 可以接受第二个参数 increaseCount(state) { state.count++; } } }) new Vue({ store, render: h => h(App), }).$mount('#app')
App.vue
<template> <div id="app"> <h1>count: {{count}}</h1> <button @click="increaseCount">点我++</button> </div> </template> <script> export default { name: "app", computed: { count() { // 获取状态数据 return this.$store.state.count; } }, methods: { increaseCount() { // 修改状态数据 this.$store.commit("increaseCount"); }r } }; </script>
项目实战
业务目标
1、制作一个需要账号登录的课程学习项目
2、不同的课程需要不同的会员等级,实现购买会员的功能,课程分享
项目功能
1、通过state.userinfo控制用户登录路由限制
2、多组件共享state.userStatus 和 state.vipLevel状态
3、多组件修改state.userstatus 和 state.vipLevel状态
文件目录树
src ├── App.vue ├── main.js ├── router.js ├── store │ ├── actions.js │ ├── getters.js │ ├── index.js │ ├── mutations.js │ └── state.js └── views ├── Home.vue └── Login.vue
文件代码
App.vue
<template> <div id="app"> <router-view/> </div> </template>
main.js
import Vue from 'vue' import App from './App.vue' import store from './store' import router from './router' import Vant from 'vant'; import 'vant/lib/index.css'; Vue.use(Vant); Vue.config.productionTip = false // 前置守卫,权限校验 router.beforeEach((to, from, next) => { if (store.state.username || to.path === "/login") { next() } else { next({ path: "/login" }) } }) new Vue({ store, router, render: h => h(App) }).$mount('#app')
router.js
import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' Vue.use(Router) export default new Router({ mode: 'history', base: process.env.BASE_URL, routes: [{ path: '/', name: 'Home', component: Home }, { path: '/login', name: 'Login', component: () => import ('./views/Login.vue') } ] })
store/actions.js
export default { buyVip({ commit }, username) { return new Promise((resolve, reject) => { // 模拟后端交互耗时 setTimeout(() => { commit("setUserInfo", username) resolve("购买成功") }, 1000) }) } }
store/getters.js
export default { getUserLevel(state) { switch (state.username) { case "admin": return "管理员"; case "user": return "会员"; default: return "普通用户" } } }
store/index.js
import Vuex from 'vuex' import Vue from 'vue' import state from './state' import mutations from './mutations' import getters from './getters' import actions from './actions' Vue.use(Vuex) const store = new Vuex.Store({ state, getters, actions, // 异步操作 mutations // 同步操作 }) export default store
store/mutations.js
export default { setUserInfo(state, username) { state.username = username; } }
store/state.js
export default { username: "", password: "" }
views/Home.vue
<template> <div> <h1>详情页</h1> <p>欢迎登录:</p> <p>{{this.$store.getters.getUserLevel}}</p> <p>{{getUserLevel}}</p> <p>{{this.$store.state.username }}</p> <p>{{username}}</p> <van-button type="primary" @click="byVip" size="large">购买会员</van-button> </div> </template> <script> import { mapGetters, mapState } from "vuex"; export default { computed: { // 解构 ...mapGetters(["getUserLevel"]), ...mapState(["username"]) }, methods: { byVip() { this.$store.dispatch("buyVip", "user").then(res => { this.$dialog.alert({ message: res }); }); } } }; </script>
views/Login.vue
<template> <div style="margin: 20px;"> <div style="text-align: center;background-color:#EEEEEE"> <h1>登录</h1> </div> <van-cell-group> <van-field v-model="username" label="用户名" placeholder="请输入用户名" required /> <van-field v-model="password" @keyup.enter.native="login" label="密码" type="password" placeholder="请输入密码" required /> <div style="margin-top:30px"> <van-button type="primary" @click="login" size="large">登录</van-button> </div> </van-cell-group> </div> </template> <script> export default { data() { return { username: "", password: "" }; }, methods: { login() { if (this.username !== "" && this.password !== "") { this.$store.commit("setUserInfo", this.username); this.$router.push({ path: "/" }); } else { this.$dialog.alert({ message: "登录失败" }); } } } }; </script>