Vue状态管理之vuex
<p><code></p>
<p>初步认识<a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>x<br />1)<a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>x是一个专为Vue.js应用程序开发的转态管理模式;集中存储和管理应用的所有组件状态。<br />2)使用场景:<br />处理多组件依赖于同一个数据<br />一个组件的行为——改变数据——影响另一个组件的视图(共用依赖的数据)<br />Vuex将组件公用数据抽离,在一个公共仓库管理,使得各个组件容易获取(getter)数据,也容易设置数据(setter)。</p>
<p>Vuex之store<br />1)Store类就是在存储数据和管理数据方法的仓库,实现方式就是将数据和方法以对象形式传入其实例中。要注意一个应用或项目中只能存在一个Store实例。</p>
<p>sate<br />用来存放组件之间共享的数据</p>
<p>mutations(只能处理同步函数)<br />改变状态(state)的唯一方式是通过提交(commit)一个mutation</p>
<p>getters<br />对state的数据进行筛选,过滤</p>
<p>actions(可以包含任意异步操作,ajax、<a href="http://www.js-code.com/tag/setTimeout" title="setTimeout" target="_blank">setTimeout</a>、<a href="http://www.js-code.com/tag/setInterval" title="setInterval" target="_blank">setInterval</a>)</p>
<p><a href="https://vuex.vuejs.org/zh/installation.html" rel="nofollow noreferrer" target="_blank">https://vuex.vuejs.org/zh/ins...</a></p>
<p><strong>1)安装</strong></p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="npm install vuex --save
或
yarn add vuex" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs sql"><code>npm <span class="hljs-keyword">install</span> vuex <span class="hljs-comment">--save</span>
或
yarn <span class="hljs-keyword">add</span> vuex</code></pre>
<p>在一个模块化的打包系统中,您必须显示地通过Vue.use()来安装Vuex:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs typescript"><code><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> Vuex <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span>
Vue.use(Vuex)</code></pre>
<p>当使用全局script标签引用Vuex时,不需要以上安装过程</p>
<p>Vuex依赖<a href="http://www.js-code.com/tag/promis" title="Promis" target="_blank">Promis</a>e(不支持promise的浏览器)</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script></p>
<p>npm install es6-promise --save # npm<br />
yarn add es6-promise # Yarn<br />
import 'es6-promise/auto'<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs coffeescript"><code><script src=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"</span>></script>
<span class="hljs-built_in">npm</span> install es6-promise --save <span class="hljs-comment"># npm</span>
yarn add es6-promise <span class="hljs-comment"># Yarn</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'es6-promise/auto'</span>
</code></pre>
<p><strong>2)<a href="http://www.js-code.com/tag/state" title="State" target="_blank">State</a></strong><br />Vuex使用单一状态树,用一个对象包含了全部的应用层级状态。这也意味着,每个应用将仅仅包含一个store实例。(由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性(computed)中返回即可。)<br />在Vue组件中获得Vuex状态<br />最简单的方法是在计算属性中返回某个状态</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="// 创建一个 Counter 组件<br />
<a href="http://www.js-code.com/tag/const" title="const" target="_blank">const</a> Counter = {<br />
template: `</p>
<div>{{ count }}</div>
<p>`,<br />
computed: {<br />
count () {<br />
return store.state.count<br />
}<br />
}<br />
}" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs swift"><code><span class="hljs-comment">// 创建一个 Counter 组件</span>
const <span class="hljs-type">Counter</span> = {
template: `<div>{{ <span class="hljs-built_in">count</span> }}</div>`,
computed: {
<span class="hljs-built_in">count</span> () {
<span class="hljs-keyword">return</span> store.state.<span class="hljs-built_in">count</span>
}
}
}</code></pre>
<p>然而,这种模式导致组件依赖全局状态单例。在模块化的构建系统中,在每个需要使用 state 的组件中需要频繁地导入,并且在测试组件时需要模拟状态。</p>
<p>Vue通过store选项,提供了一种机制将状态从根组件“注入”到每个子组件中(需要调用Vue.use(Vuex))</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<a href="http://www.js-code.com/tag/const" title="const" target="_blank">const</a> app = <a href="http://www.js-code.com/tag/new" title="new" target="_blank">new</a> Vue({<br />
el: '#app',<br />
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件<br />
store,<br />
components: { Counter },<br />
template: `</p>
<div class="app">
<counter></counter>
</div>
<p> `<br />
})<br />
<a href="http://www.js-code.com/tag/const" title="const" target="_blank">const</a> Counter = {<br />
template: `</p>
<div>{{ count }}</div>
<p>`,<br />
computed: {<br />
count () {<br />
return this.$store.state.count<br />
}<br />
}<br />
}<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs kotlin"><code><span class="hljs-keyword">const</span> app = new Vue({
el: <span class="hljs-string">'#app'</span>,
<span class="hljs-comment">// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件</span>
store,
components: { Counter },
template: `
<div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">app</span>"></span>
<counter></counter>
</div>
`
})
<span class="hljs-keyword">const</span> Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.$store.state.count
}
}
}
</code></pre>
<p>map<a href="http://www.js-code.com/tag/state" title="State" target="_blank">State</a>辅助函数</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,</p>
<p> // 传字符串参数 'count' 等同于 `state => state.count`<br />
countAlias: 'count',</p>
<p> // 为了能够使用 `this` 获取局部状态,必须使用常规函数<br />
countPlusLocalState (state) {<br />
return state.count + this.localCount<br />
}<br />
})<br />
}</p>
<p>computed: mapState([<br />
// 映射 this.count 为 store.state.count<br />
'count'<br />
])<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs typescript"><code><span class="hljs-comment">// 在单独构建的版本中辅助函数为 Vuex.mapState</span>
<span class="hljs-keyword">import</span> { mapState } <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
<span class="hljs-comment">// ...</span>
computed: mapState({
<span class="hljs-comment">// 箭头函数可使代码更简练</span>
count: <span class="hljs-function"><span class="hljs-params">state</span> =></span> state.count,
<span class="hljs-comment">// 传字符串参数 'count' 等同于 `state => state.count`</span>
countAlias: <span class="hljs-string">'count'</span>,
<span class="hljs-comment">// 为了能够使用 `this` 获取局部状态,必须使用常规函数</span>
countPlusLocalState (state) {
<span class="hljs-keyword">return</span> state.count + <span class="hljs-keyword">this</span>.localCount
}
})
}
computed: mapState([
<span class="hljs-comment">// 映射 this.count 为 store.state.count</span>
<span class="hljs-string">'count'</span>
])
</code></pre>
<p>对象展开运算符(mapState函数返回的是一个对象)</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="computed: {
localComputed () { /* ... */ },
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs groovy"><code><span class="hljs-string">computed:</span> {
localComputed () { <span class="hljs-comment">/* ... */</span> },
<span class="hljs-comment">// 使用对象展开运算符将此对象混入到外部对象中</span>
...mapState({
<span class="hljs-comment">// ...</span>
})
}
</code></pre>
<p><strong>3)Getter</strong><br />Vuex允许我们在store中定义“getter”(可以认为是store的计算属性)。就像是计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。(一般用于派生状态)<br />Getter接受state做为其第一个参数:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {<br />
return state.todos.filter(todo => todo.done)<br />
}<br />
}<br />
})<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs groovy"><code>const store = <span class="hljs-keyword">new</span> Vuex.Store({
<span class="hljs-symbol"> state:</span> {
<span class="hljs-symbol"> todos:</span> [
{ <span class="hljs-string">id:</span> <span class="hljs-number">1</span>, <span class="hljs-string">text:</span> <span class="hljs-string">'...'</span>, <span class="hljs-string">done:</span> <span class="hljs-literal">true</span> },
{ <span class="hljs-string">id:</span> <span class="hljs-number">2</span>, <span class="hljs-string">text:</span> <span class="hljs-string">'...'</span>, <span class="hljs-string">done:</span> <span class="hljs-literal">false</span> }
]
},
<span class="hljs-symbol"> getters:</span> {
<span class="hljs-symbol"> doneTodos:</span> state => {
<span class="hljs-keyword">return</span> state.todos.filter(todo => todo.done)
}
}
})
</code></pre>
<p>Getter会暴露store.getters对象,可以以属性的形式访问这些值:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="getters: {
// ...
doneTodosCount: (state, getters) => {<br />
return getters.doneTodos.length<br />
}<br />
}<br />
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs coffeescript"><code>getters: {
<span class="hljs-regexp">//</span> ...
doneTodosCount: <span class="hljs-function"><span class="hljs-params">(state, getters)</span> =></span> {
<span class="hljs-keyword">return</span> getters.doneTodos.length
}
}
store.getters.doneTodos <span class="hljs-regexp">//</span> -> [{ id: <span class="hljs-number">1</span>, text: <span class="hljs-string">'...'</span>, done: <span class="hljs-literal">true</span> }]</code></pre>
<p>注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。</p>
<p>你也可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="数组" target="_blank">数组</a>进行查询时非常有用。</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="getters: {
// ...
getTodoById: (state) => (id) => {<br />
return state.todos.find(todo => todo.id === id)<br />
}<br />
}<br />
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs typescript"><code>getters: {
<span class="hljs-comment">// ...</span>
getTodoById: <span class="hljs-function">(<span class="hljs-params">state</span>) =></span> (id) => {
<span class="hljs-keyword">return</span> state.todos.find(<span class="hljs-function"><span class="hljs-params">todo</span> =></span> todo.id === id)
}
}
store.getters.getTodoById(<span class="hljs-number">2</span>) <span class="hljs-comment">// -> { id: 2, text: '...', done: false }</span>
</code></pre>
<p>mapGetters辅助函数<br />mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs typescript"><code><span class="hljs-keyword">import</span> { mapGetters } <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
<span class="hljs-comment">// ...</span>
computed: {
<span class="hljs-comment">// 使用对象展开运算符将 getter 混入 computed 对象中</span>
...mapGetters([
<span class="hljs-string">'doneTodosCount'</span>,
<span class="hljs-string">'anotherGetter'</span>,
<span class="hljs-comment">// ...</span>
])
}
}</code></pre>
<p>如果你想将一个getter属性另取一个名字,使用对象形式</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs ruby"><code>mapGetters({
<span class="hljs-regexp">//</span> 把 <span class="hljs-string">`this.doneCount`</span> 映射为 <span class="hljs-string">`this.$store.getters.doneTodosCount`</span>
<span class="hljs-symbol">doneCount:</span> <span class="hljs-string">'doneTodosCount'</span>
})
</code></pre>
<p><strong>4)Mutation</strong><br />更改Vuex的store中的状态的唯一方法是提交mutation。Vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs properties"><code><span class="hljs-attr">const</span> <span class="hljs-string">store = new Vuex.Store({</span>
<span class="hljs-attr">state</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">count</span>: <span class="hljs-string">1</span>
<span class="hljs-attr">},</span>
<span class="hljs-attr">mutations</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">increment</span> <span class="hljs-string">(state) {</span>
<span class="hljs-meta">//</span> <span class="hljs-string">变更状态</span>
<span class="hljs-attr">state.count++</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">})</span></code></pre>
<p>你不能直接调用一个mutation handler。这个选项更像是事件注册:"当触发一个类型为<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>crement的mutation时,调用此函数。"要唤醒一个mutation handler,你需要以相应的type调用store.commit方法:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="store.commit('increment')
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs scala"><code>store.commit(<span class="hljs-symbol">'incremen</span>t')
</code></pre>
<p>你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// ...
mutations: {
increment (state, n) {
state.count += n
}
}
store.commit('increment', 10)
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs groovy"><code><span class="hljs-comment">// ...</span>
<span class="hljs-string">mutations:</span> {
increment (state, n) {
state.count += n
}
}
store.commit(<span class="hljs-string">'increment'</span>, <span class="hljs-number">10</span>)
</code></pre>
<p>在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的mutation会更易读:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// ...
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit('increment', {
amount: 10
})
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs groovy"><code><span class="hljs-comment">// ...</span>
<span class="hljs-string">mutations:</span> {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit(<span class="hljs-string">'increment'</span>, {
<span class="hljs-symbol"> amount:</span> <span class="hljs-number">10</span>
})
</code></pre>
<p>提交mutation的另一种方式是直接使用包含type属性的对象</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="store.commit({
type: 'increment',
amount: 10
})
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs properties"><code><span class="hljs-attr">store.commit({</span>
<span class="hljs-attr">type</span>: <span class="hljs-string">'increment',</span>
<span class="hljs-attr">amount</span>: <span class="hljs-string">10</span>
<span class="hljs-attr">})</span>
<span class="hljs-attr">mutations</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">increment</span> <span class="hljs-string">(state, payload) {</span>
<span class="hljs-meta">state.count</span> <span class="hljs-string">+= payload.amount</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">}</span></code></pre>
<p>mutation必须是同步函数</p>
<p><strong>5)Action</strong><br />Action类似于mutation,不同在于:<br /><strong>Action提交的是mutation,而不是直接变更状态。</strong><br /><strong>Action可以包含任意异步操作</strong></p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs properties"><code><span class="hljs-attr">const</span> <span class="hljs-string">store = new Vuex.Store({</span>
<span class="hljs-attr">state</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">count</span>: <span class="hljs-string">0</span>
<span class="hljs-attr">},</span>
<span class="hljs-attr">mutations</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">increment</span> <span class="hljs-string">(state) {</span>
<span class="hljs-attr">state.count++</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">},</span>
<span class="hljs-attr">actions</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">increment</span> <span class="hljs-string">(context) {</span>
<span class="hljs-attr">context.commit('increment')</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">})</span></code></pre>
<p>Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。</p>
<p>Action通过store.dispatch方法触发:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="store.dispatch('increment')
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs scala"><code>store.dispatch(<span class="hljs-symbol">'incremen</span>t')
</code></pre>
<p>我们可以在 action 内部执行异步操作:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="actions: {
incrementAsync ({ commit }) {
setTimeout(() => {<br />
commit('increment')<br />
}, 1000)<br />
}<br />
}</p>
<p>Actions 支持同样的载荷方式和对象方式进行分发:<br />
// 以载荷形式分发<br />
store.dispatch('incrementAsync', {<br />
amount: 10<br />
})</p>
<p>// 以对象形式分发<br />
store.dispatch({<br />
type: 'incrementAsync',<br />
amount: 10<br />
})<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs typescript"><code>actions: {
incrementAsync ({ commit }) {
setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
commit(<span class="hljs-string">'increment'</span>)
}, <span class="hljs-number">1000</span>)
}
}
Actions 支持同样的载荷方式和对象方式进行分发:
<span class="hljs-comment">// 以载荷形式分发</span>
store.dispatch(<span class="hljs-string">'incrementAsync'</span>, {
amount: <span class="hljs-number">10</span>
})
<span class="hljs-comment">// 以对象形式分发</span>
store.dispatch({
<span class="hljs-keyword">type</span>: <span class="hljs-string">'incrementAsync'</span>,
amount: <span class="hljs-number">10</span>
})
</code></pre>
<p>store.dispatch 可以处理被触发的 action 的处理函数返回的 <a href="http://www.js-code.com/tag/promise" title="Promise" target="_blank">Promise</a>,并且 store.dispatch 仍旧返回 <a href="http://www.js-code.com/tag/promis" title="Promis" target="_blank">Promis</a>e:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {<br />
setTimeout(() => {<br />
commit('someMutation')<br />
resolve()<br />
}, 1000)<br />
})<br />
}<br />
}<br />
store.dispatch('actionA').then(() => {<br />
// ...<br />
})<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs coffeescript"><code>actions: {
actionA ({ commit }) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Promise(<span class="hljs-function"><span class="hljs-params">(resolve, reject)</span> =></span> {
setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
commit(<span class="hljs-string">'someMutation'</span>)
resolve()
}, <span class="hljs-number">1000</span>)
})
}
}
store.dispatch(<span class="hljs-string">'actionA'</span>).<span class="hljs-keyword">then</span>(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
<span class="hljs-regexp">//</span> ...
})
</code></pre>
<p><strong>6)Module</strong><br />由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。<br />为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态<br />
store.state.b // -> moduleB 的状态<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs properties"><code><span class="hljs-attr">const</span> <span class="hljs-string">moduleA = {</span>
<span class="hljs-attr">state</span>: <span class="hljs-string">{ ... },</span>
<span class="hljs-attr">mutations</span>: <span class="hljs-string">{ ... },</span>
<span class="hljs-attr">actions</span>: <span class="hljs-string">{ ... },</span>
<span class="hljs-attr">getters</span>: <span class="hljs-string">{ ... }</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">const</span> <span class="hljs-string">moduleB = {</span>
<span class="hljs-attr">state</span>: <span class="hljs-string">{ ... },</span>
<span class="hljs-attr">mutations</span>: <span class="hljs-string">{ ... },</span>
<span class="hljs-attr">actions</span>: <span class="hljs-string">{ ... }</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">const</span> <span class="hljs-string">store = new Vuex.Store({</span>
<span class="hljs-attr">modules</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">a</span>: <span class="hljs-string">moduleA,</span>
<span class="hljs-attr">b</span>: <span class="hljs-string">moduleB</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">})</span>
<span class="hljs-meta">store.state.a</span> <span class="hljs-string">// -> moduleA 的状态</span>
<span class="hljs-meta">store.state.b</span> <span class="hljs-string">// -> moduleB 的状态</span>
</code></pre>
<p>对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const moduleA = {
state: { count: 0 },
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs properties"><code><span class="hljs-attr">const</span> <span class="hljs-string">moduleA = {</span>
<span class="hljs-attr">state</span>: <span class="hljs-string">{ count: 0 },</span>
<span class="hljs-attr">mutations</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">increment</span> <span class="hljs-string">(state) {</span>
<span class="hljs-meta">//</span> <span class="hljs-string">这里的 `state` 对象是模块的局部状态</span>
<span class="hljs-attr">state.count++</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">},</span>
<span class="hljs-attr">getters</span>: <span class="hljs-string">{</span>
<span class="hljs-attr">doubleCount</span> <span class="hljs-string">(state) {</span>
<span class="hljs-attr">return</span> <span class="hljs-string">state.count * 2</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">}</span>
<span class="hljs-attr">}</span>
</code></pre>
<p>同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs typescript"><code><span class="hljs-keyword">const</span> moduleA = {
<span class="hljs-comment">// ...</span>
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
<span class="hljs-keyword">if</span> ((state.count + rootState.count) % <span class="hljs-number">2</span> === <span class="hljs-number">1</span>) {
commit(<span class="hljs-string">'increment'</span>)
}
}
}
}
</code></pre>
<p>对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs kotlin"><code><span class="hljs-keyword">const</span> moduleA = {
<span class="hljs-comment">// ...</span>
getters: {
sumWithRootCount (state, getters, rootState) {
<span class="hljs-keyword">return</span> state.count + rootState.count
}
}
}
</code></pre>
<p>默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="项目结构
├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js # 产品模块" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs css"><code>项目结构
├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.html</span>
├── <span class="hljs-selector-tag">main</span><span class="hljs-selector-class">.js</span>
├── <span class="hljs-selector-tag">api</span>
│ └── ... # 抽取出<span class="hljs-selector-tag">API</span>请求
├── <span class="hljs-selector-tag">components</span>
│ ├── <span class="hljs-selector-tag">App</span><span class="hljs-selector-class">.vue</span>
│ └── ...
└── <span class="hljs-selector-tag">store</span>
├── <span class="hljs-selector-tag">index</span><span class="hljs-selector-class">.js</span> # 我们组装模块并导出 <span class="hljs-selector-tag">store</span> 的地方
├── <span class="hljs-selector-tag">actions</span><span class="hljs-selector-class">.js</span> # 根级别的 <span class="hljs-selector-tag">action</span>
├── <span class="hljs-selector-tag">mutations</span><span class="hljs-selector-class">.js</span> # 根级别的 <span class="hljs-selector-tag">mutation</span>
└── <span class="hljs-selector-tag">modules</span>
├── <span class="hljs-selector-tag">cart</span><span class="hljs-selector-class">.js</span> # 购物车模块
└── <span class="hljs-selector-tag">products</span><span class="hljs-selector-class">.js</span> # 产品模块</code></pre>
<h4>交流与学习qq:759020213</h4>
<p></code></p>