关键词:Vuex
VueX可以帮助我们管理共享状态,并附带了更多的概念和框架,在大型单页面应用或特殊使用场景中,可以帮我们更好地将一些共用数据提取出来进行管理
基本用法
(不以webpack打包的项目结构演示,直接在页面demo中演示)
在本地环境下获取vuex.js,然后通过<script>标签进行引入
<script src="./js/vuex.js"></script>
新建Vuex对象:
const store = new Vuex.Store({
//vuex的配置内容
})
仓库store 包含了应用的数据(状态)和操作过程,Vuex里的数据都是响应式的,任何组件使用同一 store 的数据时,只要 store 的数据变化,对应的组件也会立即更新
数据保存在 Vuex 选项的 state 字段内,例如实现一个计数器,定义一个数据 count,初始值为0 :
<body>
<div id="app">
{{$store.state.count}}
</div>
<script>
const store = new Vuex.Store({
state:{
count:0
}
})
var vm = new Vue({
el:'#app',
store
})
</script>
</body>
此时,计数0就显示出来了,但在组件内,来自store的数据只能读取,不能手动修改,改变 store 中数据的唯一途径就是显示地提交 mutations 。
mutations 是Vuex 的第二个选项,用来直接修改state里的数据,我们给上面的计数器增加两个mutations ,用来+1和-1,并将插值表达式的{{$store.state.count}}写到计算方法中:
<body>
<div id="app">
{{count}}
<button @click="handleIncrement">+1</button>
<button @click="handleDecrease">-1</button>
</div>
<script>
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state){
state.count++
},
decrease(state){
state.count--
}
}
})
var vm = new Vue({
el:'#app',
computed:{
count(){
return this.$store.state.count
}
},
methods:{
handleIncrement(){
this.$store.commit('increment')
},
handleDecrease(){
this.$store.commit('decrease')
}
},
store
})
</script>
</body>
在组件内部,通过 this.$store.commit 方法来执行 mutations,组件只负责提交一个事件名,Vuex 对应的mutaions 来完成业务逻辑。
提交 mutations 的另一种方法是直接使用包含 type 属性的对象,例如:
mutations:{
increment(state,params){
state.count += params.count
}
}
this.$store.commit({
type:'increment',
count:1
})
高级用法
Vuex 还有其他3个选项可以使用: getters、actions、modules
假设有这样一个场景,Vuex 定义了某个数据 list,它是一个数组,比如:
const store = new Vuex.Store({
state:{
list:[1,5,8,10,30,50]
}
})
如果只想得到小于10的数据,可以直接在组件内部的计算方法中利用
return this.$store.state.list.filter(item => item < 10)
的方式实现,但如果还有其他组件也需要用到过滤后的数据,就需要重写一份一模一样的代码,这样对它们的使用和维护都不方便。
getters就是起这个作用的,它能把 computed 的方法提取出来:
<div id="app">
{{list}}
</div>
<script>
const store = new Vuex.Store({
state:{
list:[1,5,8,10,30,50]
},
getters:{
filteredList(state) {
return state.list.filter(function(item){
return item<10;
})
}
}
})
var vm = new Vue({
el:'#app',
computed:{
list(){
return this.$store.getters.filteredList
}
},
store
})
</script>
这种写法与组件的计算属性十分相似,getter 也可以依赖其他 getter,把getter作为第二个参数,比如再写一个 getter,计算 list 过滤后的结果数量:
const store = new Vuex.Store({
state:{
list:[1,5,8,10,30,50]
},
getters:{
filteredList(state) {
return state.list.filter(function(item){
return item<10;
})
},
listCount(state,getters){
return getters.filteredList.length
}
}
})
var vm = new Vue({
el:'#app',
computed:{
list(){
return this.$store.getters.filteredList
},
listCount(){
return this.$store.getters.listCount
}
},
store
})
action
mutation 里不应该异步操作数据,所以有了 action 选项,action 和 mutation 很像,不同的是 action 里面提交的是 mutaion,并可以异步操作业务逻辑
action 在组件内通过$store.dispatch 触发,例如使用 action 来加1:
<div id="app">
{{count}}
<button @click="handleActionIncrement">+1</button>
</div>
<script>
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state,n=1){
state.count += n
}
},
actions:{
increment(context){
context.commit('increment')
}
}
})
var vm = new Vue({
el:'#app',
computed:{
count(){
return this.$store.state.count
}
},
methods:{
handleActionIncrement(){
this.$store.dispatch('increment')
}
},
store
})
</script>
就上述示例看来有点多此一举,但它在异步中的作用就凸显出来了,例如用一个Promise 在1秒后提交 mutaion:
<div id="app">
{{count}}
<button @click="handleAsyncIncrement">async +1</button>
</div>
<script>
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state,n=1){
state.count += n
}
},
actions:{
asyncIncrement(context){
return new Promise(resolve=>{
setTimeout(()=>{
context.commit('increment')
resolve()
},1000)
})
}
}
})
var vm = new Vue({
el:'#app',
computed:{
count(){
return this.$store.state.count
}
},
methods:{
handleAsyncIncrement(){
this.$store.dispatch('asyncIncrement').then(()=>{
console.log(this.$store.state.count)
})
}
},
store
})
</script>
mutations 、actions 看起来很相似,一般情况下,涉及改变数据的,就用 mutations ,存在业务逻辑的,就用 actions ,至于将业务逻辑放到 actions 里还是放到Vue组件里完成,就视情况而定了
moudules
最后一个选项是 modules,它用来将 store 分割到不同模块。当项目很庞大时,store 里的选项会非常多,使用 modules 可以将它们写入不同的文件中,每个 modules 拥有自己的 state、getters、mutations、actions,而且可以多层嵌套,例如:
const moduleA = {
state:{},
mutations:{},
actions:{},
getters:{}
}
const moduleB = {
state:{},
mutations:{},
actions:{},
getters:{}
}
const store = new Vuex.Store({
modules:{
a:moduleA,
b:moduleB
}
})
此时,在组件中使用 $store.state.a就可以获取moduleA的状态
module 的 mutation 和 getter 接收的第一个参数 state 是当前模块的状态,在actions 和 getters 中,还可以接收一个参数 rootState,来访问根节点的状态,例如:
const moduleA = {
state:{
count:0
},
getters:{
sumCount(state,getters,rootState){
return state.count + rootState.count
}
}
}
Comments NOTHING