由于多個狀態分散的跨越在許多組件和交互間各個角落,大型應用復雜度也經常逐漸增長。為了解決這個問題,Vue 提供 vuex:我們有受到 Elm 啟發的狀態管理庫。vuex 甚至集成到 vue-devtools,無需配置即可訪問時光旅行。
前言
如果你對vuex狀態管理還不是很了解的話,請先閱讀
在本篇,我將演示如何使用
- vue-cli ( https://github.com/vuejs/vue-cli )
- Vue ( https://cn.vuejs.org/v2/guide/ )
- Vuex ( https://vuex.vuejs.org/zh-cn/intro.html )
來完成一個 小型demo的制作(點擊按鈕,計數器自增)。
環境搭建
vue-cli & webpack
在任意目錄下打開控制臺, 輸入
vue init webpack counter
image
中間的項目可以隨便填選,但最后一項是否自動安裝依賴一定要選 No
cnpm
npm 依賴有一些是國外的,安裝比較慢還容易出錯誤.
命令行輸入 :
npm install cnpm -g --registry=https://registry.npm.taobao.org
安裝國內淘寶鏡像源的cnpm.
使用cnpm 安裝項目依賴 :
cnpm install
安裝Vuex :
cnpm i vuex -S
啟動項目服務 :
npm start
項目開發
目錄結構
image
源代碼
1. 建立store, 存放在store.js
import Vue from 'vue'
import Vuex from 'vuex'
// Vue 引入Vue插件方式
Vue.use(Vuex)
export default new Vuex.Store({
state: {
counter: 0
},
getters: {
counter: state => state.counter
},
mutations: {
addCounter (state) {
state.counter ++
}
}
})
2. 修改webpack的入口文件 main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
// 引入建立好的 store
import store from './store'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
// 綁定到 Vue 實例上
store,
template: '<App/>',
components: { App }
})
將store綁定到Vue實例上之后,可以在每個組件中 使用 this.$store 進行操作.
3. 建立 計數器 組件 Counter.vue
<template>
<div>
<h1>counter: {{counter}}</h1>
<button @click="addCounter">add counter</button>
</div>
</template>
<script>
import { mapMutations, mapGetters } from 'vuex'
export default {
name: 'Counter',
computed: mapGetters([
'counter'
]),
methods: mapMutations([
'addCounter'
])
}
</script>
當然, Vuex 提供了 一種 十分友好的方式讓組件引用store 中的屬性和方法 :
- getters 對應 mapGetters
- mutations 對應 mapMutations
- actions 對應mapActions
使用方式 :
<script>
import { mapMutations, mapGetters } from 'vuex'
export default {
name: 'Counter',
computed: mapGetters([
'counter'
]),
methods: mapMutations([
'addCounter'
])
}
</script>
或者
<script>
import { mapMutations, mapGetters } from 'vuex'
export default {
name: 'Counter',
computed: mapGetters({
counter: 'counter'
}),
methods: mapMutations({
addCounter: 'addCounter'
})
}
</script>
如果methods和computed中 存在組件的私有屬性和方法, 那么可以使用 ES6 對象展開運算符
<script>
import { mapMutations, mapGetters } from 'vuex'
export default {
name: 'Counter',
computed: {
...mapGetters([
'counter'
]),
selfProperty () {
return 'self property'
}
},
methods: {
...mapMutations([
'addCounter'
]),
selfMethod () {
return 'self method'
}
}
}
</script>
4. 在 根組件 上掛載 Counter, App.vue
<template>
<div id="app">
<counter></counter>
</div>
</template>
<script>
import Counter from './components/Counter.vue'
export default {
name: 'app',
components: {
Counter
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
運行結果
image
image
最后
本節源碼 :
https://github.com/lonelydawn/counter
下一節我們將探討一個更復雜的案例, 實戰用戶需求