参照官网整理总结vuex语法。
计划日期:
Vuex基础部分:2022年2月20日——2022年2月28日
Vuex源码相关实践:待定
Vuex拓展:待定
写完后,会发到仓库地址:待定
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
store——包含以上概念的容器
view——以声明方式将 state 映射到视图
state 状态、数据
getters:当state的数据变更时,getters的值也发生变化(相当于vuex中state的计算属性)
mutations 更改状态的函数
actions 异步操作
Modules 模块。为了将store的状态进行分割,每个模块都有属于自己的state、mutation、action、getter
Vuex V3.0
基础代码:
import Vue from 'vue'
import Vuex from 'vuex'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
Vue.use(Vuex)//使用vuex
// 将 store 实例作为插件安装
const store = new Vuex.Store({
/*状态、数据 存储 */
state: {
count: 0
},
/* 行为,更改状态的函数 */
mutations: {
increment(state) {
state.count++
}
}
})
new Vue({
router,
store,// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
render: function (h) {
return h(App)
}
}).$mount('#app')
state——状态、数据
状态、数据 **单一状态树 **作为一个“唯一数据源 (SSOT (opens new window))”而存在。
操作:
读取state中数据
this.$store.state.count
变更state中的数据
//使用commit调用mutations内的increment方法
this.$store.commit("increment")
mapState
辅助函数
计算属性显示数据
作用:当获取多个状态减少申明多个状态的重复和冗余,使用辅助函数来生成计算属性。
main.js
import Vue from 'vue'
import Vuex from 'vuex'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
// 将 store 实例作为插件安装
Vue.use(Vuex)
const store = new Vuex.Store({
/*状态、数据 存储 */
state: {
count: 0,
c: 1,
},
/* 行为,更改状态的函数 */
mutations: {
increment(state) {
state.count++
}
}
})
new Vue({
router,
store,
render: function (h) {
return h(App)
}
}).$mount('#app')
home.vue
<template>
<div>
首页
<p>{{ count }}</p>
<p>{{ countPlusLocalState }}</p>
<p>{{ countAlias }}</p>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
localCount: 123,
};
},
//监听属性 类似于data概念
computed: mapState({
// 箭头函数可使代码更简练
count: (state) => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: "count",
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState(state) {
return state.count + this.localCount;
},
}),
// computed: mapState(["count"]),
//监控data中的数据变化
watch: {},
//方法集合
methods: {
increment() {
/* 获取state内的数据值 */
this.$store.commit("increment");
console.log(this.$store.state.count);
},
},
};
</script>
简写形式
当计算属性名称和state的数据名称相同可以简写成数组形式
computed: mapState(["count"]),
页面内调用:
{{count}}
展开mapstate对象方便调用
<template>
<div>
首页
<p>{{ count }}</p>
<p>{{ c }}</p>
<!-- <p>{{ countPlusLocalState }}</p> -->
<!-- <p>{{ countAlias }}</p> -->
</div>
</template>
<script>
computed: {
//写法1
...mapState(["count", "c"]),
//写法2
...mapState({
count: "count",
c: "c",
}),
},
</script>
Getter——store内的计算属性
当state内的数据变化后,getter内的数据也随之变化
属性访问
Getter(state,getters)
state——(必填)返回state状态数据内的值
示例:`state.count++`
getters——(可选)调用getters内的方法
示例:`getters.todolist.length`
完整示例:
vuex书写:
const store = new Vuex.Store({
/*状态、数据 存储 */
state: {
/* state练习 */
count: 0,
c: 1,
/* getters练习 */
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
/* 行为,更改状态的函数 */
mutations: {
/* state练习 */
increment(state) {
state.count++
}
},
getters: {
doneTodos: (state) => {
// 返回todo.done为true的列表项
return state.todos.filter(todo => todo.done)
},
// 返回完整的列表
todolist: (state) => {
return state.todos;
},
// 接受其他getters作为第2个参数
doneTodosCount(state, getters) {
console.log(getters.todolist)
return getters.todolist.length
}
}
})
vue页面显示数据
<template>
<div>
首页
<p>为true的列表:{{ doneTodos }}</p>
<p>完整的列表项:{{ todolist }}</p>
<p>完整的列表长度:{{ doneTodosCount }}</p>
</div>
</template>
<script>
export default {
computed: {
// 返回todos列表
doneTodos() {
return this.$store.getters.doneTodos;
},
todolist() {
return this.$store.getters.todolist;
},
// 返回列表长度
doneTodosCount() {
return this.$store.getters.doneTodosCount;
},
},
}
</script>
结果显示:
方法访问
通过给getters方法传递参数,从而实现返回想要的数据内容
vuex
/*状态、数据 存储 */
state: {
//...
/* getters练习 */
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
//...
//给getters方法传递参数
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
调用
<template>
<div>
<h3>通过方法访问</h3>
<p>返回指定id的列表项:{{ gettodo(2) }}</p>
</div>
</template>
<script>
//需要写在methods方法内,前面写在computed计算属性内
methods: {
/* 返回指定id的列表项 */
gettodo(id) {
return this.$store.getters.getTodoById(id);
},
//...
},
</script>
输出:
mapGetters
辅助函数
注:只能映射到计算属性中,无法映射到方法中
写法与mapState类似
原本写法:
computed: {
// 返回todos列表
doneTodos() {
return this.$store.getters.doneTodos;
},
todolist() {
return this.$store.getters.todolist;
},
// 返回列表长度
doneTodosCount() {
return this.$store.getters.doneTodosCount;
},
},
使用mapGetter写法:
写法1
import { mapGetter } from "vuex";
computed: {
...mapGetters(["doneTodos", "todolist", "doneTodosCount"]),
},
写法2
import { mapGetters } from "vuex";
computed: {
...mapGetters({
doneTodos: "doneTodos",
todolist: "todolist",
doneTodosCount: "doneTodosCount",
}),
},
输出结果:
mutations——更改state状态的函数
Vuex 的 store 中的状态的唯一方法是提交 mutation
基本格式:
type(state,mutation)
-
type:(事件类型)——命名在mutations中的函数名称
示例:
increment (state, n) { state.count += n }
increment
为事件类型 state:【必选】(数据)——store中存储的数据
-
mutation:【可选】(荷载)——调用事件类型时传递给事件的参数。
示例:
store.commit('increment', 10)
最后的10
为参数事件类型为increment
完整示例:
store
const store = new Vuex.Store({
/*状态、数据 存储 */
state: {
//...
/* mutation练习 */
mut: 1
},
/* 行为,更改状态的函数 */
mutations: {
//...
/* mutation练习 */
incrementdata(state, n) {
state.mut += n.sum
}
},
getters: {
}
})
mutation.vue
<template>
<div class="">mutation获取值:{{ mudata }}</div>
</template>
<script>
export default {
components: {},
data() {
return {
mudata: "",
};
},
methods: {
runmutation() {
this.$store.commit({
type: "incrementdata",
sum: 1,
});
console.log(this.$store.state);
this.mudata = this.$store.state.mut;
},
},
mounted() {
this.runmutation();
},
};
</script>
结果:
Mutation 必须是同步函数,异步的话导致事件无法追踪(原因在于mutation直接变更的是
State
(状态)内的数据)
mapMutations
辅助函数
和
mapGetters
跟mapState
类似
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
使用常量替代 Mutation 事件类型
const SOME_MUTATION = 'SOME_MUTATION'
import { createStore } from 'vuex'
const store = createStore({
state: { ... },
mutations: {
// 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
[SOME_MUTATION] (state) {
// 修改 state
}
}
})
示例:
const CHANGE_NAME = 'CHANGE_NAME'
mutations: {
[CHANGE_NAME](state, data) {
state.name = data
}
},
Action 行为
参数概要
目的是为了处理mutation中的异步操作,原因在于,action提交的是mutation,而mutation直接变更的是state(状态数据)内的值
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
接收1个参数
第一个参数 返回store内所有的对象(所以可以用解构赋值的方式获取指定store内的对象)
打印
increment (context)
context的数据结果
写法1.
actions: {
increment (context) {
setTimeout(() => {
context.commit('increment')
}, 1000)
}
}
写法2.
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
调用action
store.dispatch('increment')
异步调用action
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
载荷形式分发(同mutation)
// 以载荷形式分发
store.dispatch('incrementAsync', {
amount: 10
})
// 以对象形式分发
store.dispatch({
type: 'incrementAsync',
amount: 10
})
mapActions调用方式
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}
组合Action(同时触发多个action)
state: {
//...
/* action练习 */
act: 1,
},
mutations: {
//...
/* action练习 */
action(state) {
console.log(state.act)
state.act++
console.log('返回存储的值:' + state.act)
}
},
actions: {
//...
action(context) {
console.log(context);
context.commit('action')
},
/* action异步分发 */
actionA(con) {
return new Promise(
(resolve, reject) => {
setTimeout(function () {
con.commit('action')
console.log('actionA:' + con.state.act)
resolve()
}, 1000)
}
)
},
actionB(con) {
// 异步的形式调用2次action
return con.dispatch('actionA').then(() => {
con.commit('action')
console.log('actionB:' + con.state.act)
})
},
/* async await包裹异步函数写法 */
async actionA(con) {
// commit触发mutations中的action行为导致act+1,
//dispatch调用action中的action,再次触发了mutations中的action行为导致act+1,
con.commit('action', await con.dispatch('action'))//相当于异步+2
console.log('actionB调用=>A:' + con.state.act);//3
},
async actionB(con) {
await con.dispatch('actionA');//3
}
}
界面内调用:
this.$store.dispatch("actionB");
用async await 写成同步形式
/* async await包裹异步函数写法 */
async actionA(con) {
// commit触发mutations中的action行为导致act+1,
//dispatch调用action中的action,再次触发了mutations中的action行为导致act+1,
con.commit('action', await con.dispatch('action'))//相当于异步+2
console.log('actionB调用=>A:' + con.state.act);//3
},
async actionB(con) {
await con.dispatch('actionA');//3
}
module 模块分割
Vuex 允许我们将 store 分割成模块(module)
多模块注册及基本使用
思路分别写2个goods和users2个不同的模块,最后注册引入到实例中
完整的store对象【全部代码】
/* 用module之后 */
const store = new Vuex.Store({
/* 全局状态 */
state: {
name: 'ccc'
},
/* 全局状态变更 */
mutations: {},
/* 全局行为 */
actions: {},
/* 全局状态返回类似计算属性 */
getters: {},
modules: {
goods,
// users,//注册模块的方式进行注册
/* 多模块公用 */
goodslist: {
namespaced: true,//开启命名空间
/* 公用相同的模型 */
modules: {
goods1: goods,
goods2: goods,
}
}
}
})
goods模型
const goods = {
namespaced: true,
// 普通的纯对象形式申明,这个状态对象会通过引用被共享,则当多模型共用的时候数据也会发生改变【模型重用】
// state: {
// name: '默认goods',
// },
// 函数形式每个模型都是单独不会同时改变【模型重用】
state() {
return {
name: '默认goods',
}
},
// 更改状态
mutations: {
GOODS(state, data) {
state.name = data
}
},
// 行为
actions: {
change_name(state, data) {
state.commit('GOODS', data)
}
},
// 计算属性
getters: {
getname: (state) => {
return state.name + ' ' + state.name
}
},
}
export default goods;
users模型
const users = {
namespaced: true,
state: {
name: '默认users',
},
// 更改状态
mutations: {
[CHANGE_NAME](state, data) {
state.name = data
}
},
// 行为
actions: {
change_name(state, data) {
state.dispatch('CHANGE_NAME', data)
}
},
// 计算属性
getters: {
getname: (state) => {
return state.name
}
},
}
export default users;
界面调用module.vue
<template>
<div class="">
<h2>模型1:goods</h2>
<p>当前名称:{{ goods }}</p>
<p>getter获取的当前名称:{{ getname }}</p>
商品名称:<input type="text" v-model="goodsname" />
<input type="button" @click="changegoodsname" value="修改商品名称" />
<h2>多模型共用</h2>
<p>goods模型1 name值:{{ goodslist1 }}</p>
<p>goods模型2 name值:{{ goodslist2 }}</p>
<h3>注册嵌套模块</h3>
<p>goods模型3 name值:{{ goodslist3 }}</p>
<h2>模型2:users</h2>
<p>当前的名称:{{ users }}</p>
</div>
</template>
<script>
import { mapGetters, mapState, mapActions, mapMutations } from "vuex";
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return { goodsname: "123" };
},
//监听属性 类似于data概念
computed: {
...mapState({
goods: (state) => {
return state.goods.name;
},
users: (state) => {
return state.users.name;
},
goodslist1: (state) => {
return state.goodslist.goods1.name;
},
goodslist2: (state) => {
return state.goodslist.goods2.name;
},
goodslist3: (state) => {
return state.goodslist.goods2.name;
},
}),
...mapGetters("goods", {
getname: "getname",
}),
},
//监控data中的数据变化
watch: {},
//方法集合
methods: {
/* 用mutation同步修改值 */
// ...mapMutations("goods", {
// changegoods: "GOODS",
// }),
/* 用action异步修改值 */
...mapActions("goods", {
actionchangegoods: "change_name",
}),
changegoodsname() {
// this.changegoods(this.goodsname);
this.actionchangegoods(this.goodsname);
},
},
//生命周期 - 创建完成(可以访问当前this实例)
created() {},
//生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
};
</script>
模块动态注册【保留state】
// 注册模块 `myModule`
//{ preserveState: true }使模块中的state无法被覆写,保持原样【保留原始state】,注册的模块state无法写入
store.registerModule('users', users, { preserveState: false })
// 注册嵌套模块 `goodslist/myModule`(前面的goodslist必须存在的情况下才能进行嵌套)
store.registerModule(['goodslist', 'goods3'], goods, { preserveState: false })
模块重用
前面完整代码中的一部分goods1和goods2模块重用的方式写入
goods3注册模块的方式写入。用的也是同一个模块
/* 用module之后 */
const store = new Vuex.Store({
//...
modules: {
goods,
// users,//注册模块的方式进行注册
/* 多模块公用 */
goodslist: {
namespaced: true,//开启命名空间
/* 公用相同的模型 */
modules: {
goods1: goods,
goods2: goods,
}
}
}
//...
})
// 注册嵌套模块 `goodslist/myModule`(前面的goodslist必须存在的情况下才能进行嵌套)
store.registerModule(['goodslist', 'goods3'], goods, { preserveState: false })
结果展示
点击按钮,修改上方商品名称内容
在线链接【需翻墙】https://codesandbox.io/s/wonderful-night-ew7uj2?file=/src/views/module1.vue