这週要来介绍一个很好用的套件 - Vuex
看到名称应该马上可以理解他就是Vue专案在使用的套件吧xD
有看过我之前的专案开发的文章的人,应该会发现我从来没有用过 Vuex
我也是最近这两週才开始接触它的~
趁着记忆犹新时赶快把它写起来~
如果有使用不当或是有误的地方再麻烦多指教
#Vuex是什么?
万用起手式来了~
所谓的Vuex是什么呢? 他可以做到哪些事呢?
官方是这么介绍它的:
Vuex是一个专为Vue.js应用程序开发的状态管理模式。
它採用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex也集成到Vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。
blablabla...
当时看完这段介绍之后我还是不知道Vuex是在做什么xD
没关係我们继续往下看:
每一个Vuex应用的核心就是store(仓库)。
“store”基本上就是一个容器,它包含着你的应用中大部分的状态(state)。
到这边应该稍微可以理解原来它的用途是「管理资料状态的容器」
#为什么需要Vuex?
原本的做法就可以在每个元件中存放资料了,那为什么还要用Vuex呢?
通常我们的资料流向会是父传子,上层传至下层,保持数据单向流通
遇到需要从子层改变父层资料时可以使用 $emit()
呼叫父层方法进而改变数据
遇到兄弟同层之间的元件要互相影响时就会有困难了,我自己的做法是将资料放到父层再用父传子的方式处理
但是不论父传子还是兄弟互传的做法都非常的麻烦且繁琐
这时候Vuex就出现了!!
我们可以将需要用到传递的资料通通丢进Vuex管理
当元件需要使用资料时,可以使用 $store
轻鬆取得数据
且透过套件提供的 dispatch
方法,可以从任何元件去改变资料数据
那传递呢? 当然用不到啰~
透过Vuex我们可以把传递的方式取代掉,并且还是保持着资料数据单向流通
#Vuex内容
刚才有看到官方文件说「Vuex应用的核心就是store」
而 Store 就是存放资料状态的容器
那这个容器内包含着哪些东西呢?
state: 存放资料状态的物件,类似Vue元件中的 dataactions: 存放方法的物件,类似Vue元件中的 methods除了改变资料状态以外的工作,都会在这边处理mutations: 负责做改变资料状态的动作getters: 取得资料状态的方法,在取得之前也可以在这先做一些资料处理,类似Vue元件中的 computed
以上四个项目会是基本常使用到的,其他还有像是
modules: 模组化的Vuex#Vuex数据流向
在数据流向的部分
前端元件(component)会透过 ditpatch
呼叫 actions 方法
actions 再透过提交(commit)的方式呼叫 mutations
mutations 再做更新 state 中的资料状态的动作
state 更新后再将数据渲染到元件中
透过这个流程达到单向数据流的操作
#安装Vuex
基本介绍之后,就先来安装它吧~
这里以使用 Vue Cli 专案为主来说明
使用npm安装指令:
npm install vuex --save
官方还有提供其他方式如:
Yarnyarn add vuex
script引用<script src="/path/to/vue.js"></script><script src="/path/to/vuex.js"></script>
#建立基本的Store
安装完成之后来建立一个最简单的Store啰~
#Step 1
在专案下新增一个 /store 资料夹,资料夹内再新增一个 index.js 档:
src└── store └── index.js
#Step 2
开启刚刚建立的 index.js 加入基本的程式码:
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({ state: { msg: "Hello Vuex!!" },});
Step 3
在 main.js 中引用:
import store from './store'
store 要加进vue喔!!
new Vue({ ..., store,}).$mount('#app')
#Step 4
上面步骤都完成之后可以来到元件中去抓看看 msg 啰~
在元件的 computed 中使用 $store.state
来取得资料数据,可以在 App.vue 中试试看是否能抓到并渲染在画面上:
//App.vue<template> <div> {{ myMsg }} </div></template><script>export default { name: "App", computed: { myMsg() { return this.$store.state.msg; }, },};
基本的 Store 就建立完成啰!!
#建立TodoList
接着我会用不包含任何功能的TodoList来介绍后面的操作
#Step 1
像刚才 msg 一样,我们在 Store 中建一个TodoList:
export default new Vuex.Store({ state: { todolist: [ { id: 1, todo: "交女朋友", done: false }, { id: 2, todo: "财务自由", done: false }, { id: 3, todo: "当码农", done: true }, ], },});
#Step 2
在 App.vue 中抓值并渲染:
<template> <div> <ul> <li v-for="item in myTodo" :key="item.id"> {{ item.todo }} - {{ item.done ? "已完成" : "未完成" }} </li> </ul> </div></template><script>export default { name: "App", computed: { myTodo() { return this.$store.state.todolist; }, },};</script>
出来的画面长这样:
#Step 3
前置作业完成了,再来我要加上click事件来切换 [已完成] 及 [未完成] 的状态:
<li ... @click="todoDone(item.id, !item.done)"> ...</li>
对应的 todoDone() 方法:
methods: { //id: 要修改状态的资料唯一码 //done: 要修改的值 todoDone(id, done) { },},
#Step 4
再来很重要(应该从头到尾都很重要xD)
我们要使用 dispatch
来呼叫 actions
第一个参数设定要呼叫的 actions 名称
第二个参数设定要传入的值,有多个值的话就用物件的方式带入
假设要呼叫的 actions 名称也叫 todoDone,并且将 id & done 传进去:
todoDone(id, done) { this.$store.dispatch("todoDone", { id, done });},
#Step 5
回到 /store/index.js 加入 todoDone():
actions: { todoDone(context, { id, done }) { },},
说明一下 actions 的参数结构,每个 actions 会有带两个参数: myActions(context, payload)
Action函数接受一个与store实例具有相同方法和属性的context对象,因此你可以调用context.commit提交一个mutation,或者通过context.state和context.getters来获取state和getters。
我们在 context 中可以使用这些属性:
{ state, // 等同于`store.state`,若在模块中则为局部状态 rootState, // 等同于`store.state`,只存在于模块中 commit, // 等同于`store.commit` dispatch , // 等同于`store.dispatch` getters, // 等同于`store.getters` rootGetters // 等同于`store.getters`,只存在于模块中 }
第二个参数 payload 是带入的参数内容(可不带)#Step 6
接着我们可以在 actions 中使用 commit
将要修改的数据提交给 mutations 来更新:
todoDone(context, { id, done }) { context.commit('TODOLIST', { id, done });},
第一个参数设定要提交给哪个 mutations 的名称
第二个参数设定要传入的值,有多个值的话就用物件的方式带入
通常actions会有一些资料面的逻辑处理,例如呼叫ajax等等,逻辑处理结束后才会提交到mutations
但範例中因为没有这层,所以看起来像是多做了一个没有用的动作
#Step 7
接着可以加入 mutations:
mutations: { TODOLIST(state, { id, done }) { },}
这边使用了常量替代Mutation 事件类型:
使用常量替代mutation 事件类型在各种Flux 实现中是很常见的模式。这样可以使linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个app 包含的mutation 一目了然
用不用常量取决于你——在需要多人协作的大型项目中,这会很有帮助。但如果你不喜欢,你完全可以不这样做。
说明一下 mutations 的参数结构,每个 mutations 会有带两个参数: myMutations(state, payload)
#Step 8
最后就是更新资料状态
先抓到 state 中的 todolist:
let todolist = state.todolist;
使用阵列的 find()
方法抓到要改的那笔:
let todo = todolist.find((item) => { return item.id === id;});
更新 done 值:
todo.done = done;
整段会是这样:
TODOLIST(state, { id, done }) { let todolist = state.todolist; let todo = todolist.find((item) => { return item.id === id; }); todo.done = done;},
也可以合併成这样:
TODOLIST(state, { id, done }) { state.todolist.find((item) => { return item.id === id }).done = done;},
#结果
到这里就完成更新资料状态啰!!
来看看结果吧~
先到这啰~
下週继续来探讨模组化以及其他的功能!!