一,前言
上篇,介绍了 vuex 的 install 插件安装逻辑,包含以下几个点:
本篇,继续介绍 Vuex 中 State 状态的实现;
二,前文回顾
上一篇提到,当外部执行`Vue.use(Vuex)`时,
会调用 Vuex 对象上的 install 方法进行插件安装,
通过 `Vue.mixin` 全局混入的方式,将`new Vue`(根组件)时注入的 store 容器实例,
在 beforeCreate 生命周期,即组件创建前,混入到所有组件中,为所有组件添加 store 属性;
这样就实现了 store 容器实例的全局混入;
复制代码
在页面中使用 Vuex 时:
// src/App.vue
<template>
<div id="app">
商品数量: {{this.$store.state.num}} 个<br>
商品单价: 10 元<br>
订单金额: {{this.$store.getters.getPrice}} 元<br>
<button @click="$store.commit('changeNum',5)">同步更新:数量+5</button>
<button @click="$store.dispatch('changeNum',-5)">异步更新:数量-5</button>
</div>
</template>
复制代码
state、getters、commit、dispatch 这些方法均来自 store 实例
三,创建 Store 类中的 State 状态
当 new Vuex.Store
时,传入了一个配置对象:
// 实例化容器容器:Vuex.Store
const store = new Vuex.Store({state,mutation,actions});
复制代码
所以,在 Store 类的构造方法中,需要有一个配置对象 options 作为入参:
// src/vuex/store.js
// Vuex 的容器
export class Store {
constructor(options) { // options:{state, mutation, actions}
const state = options.state; // 获取 options 选项中的 state 对象
}
}
复制代码
在 Vuex 中,state 中的状态要求是响应式的,即数据变化可以触发更新的视图;
而当前 Store 类中的 state 是死值,并不具备响应式;
<template>
<div id="app">
商品数量: {{this.$store.state.num}} 个<br>
商品单价: 10 元<br>
订单金额: {{this.$store.getters.getPrice}} 元<br>
<button @click="$store.commit('changeNum',5)">同步更新:数量+5</button>
<button @click="$store.dispatch('changeNum',-5)">异步更新:数量-5</button>
<!-- 测试 State 数据响应式 -->
<button @click="$store.state.num = 100">测试 State 数据响应式</button>
</div>
</template>
复制代码
通过点击页面中的按钮,直接修改 $store 中的 State 值,页面是不会更新的;
视图没有跟进的原因:因为 num 并不是响应式数据,不会进行依赖收集,数据变化后不会更新;
四,实现 State 状态的响应式
实现 State 数据的响应式,可以将 State 数据放到 vue 的 data 中,借助 Vue 的响应式实现:
// src/vuex/store.js
export class Store {
constructor(options) { // options:{state, mutation, actions}
const state = options.state; // 获取 options 选项中的 state 对象
// 响应式数据:new Vue({data})
this._vm = new Vue({
data: {
// 在 data 中,默认不会将以$开头的属性挂载到 vm 上
$$state: state // $$state 对象将通过 defineProperty 进行属性劫持
}
})
}
get state() { // 对外提供属性访问器:当访问state时,实际是访问 _vm._data.$$state
return this._vm._data.$$state
}
}
复制代码
这里有一个技巧:在 Vue 中,以$开头的属性是内部的,默认不会被挂载到 vm 上的;
即不能通过 vm.$$state 获取,只能通过 _vm._data.$$state 访问,而 _data 是素有属性;
复制代码
当外部通过 store.state 获取状态对象时,相当于拿到了 this._vm._data.$$state
,get state()是 ES6 语法属性访问器,相当于 Object.defineProperty({}) 中的 getter ;
// todo _data 相关知识可联动 Vue2.x 源码的《数据代理实现》
总结:
vuex 中 state 状态的响应式是借助了 Vue 来实现的;
响应式数据在页面渲染时会进行依赖收集,
当 store 中的 state 状态改变时,就会触发视图的更新操作;
复制代码
五,结尾
本篇,介绍了 Vuex 中 State 状态的实现,主要涉及以下几个点:
创建 Store 类中的 State 状态;
借助 Vue 实现 State 状态的响应式;
下一篇, Vuex 中 getter 的实现;
评论