vuex 是一个专门为vue.js 应用程序开发的状态管理模式。它采用集中式储存管理应用的所有组件的状态,并以响应的规则保证状态以一种可预测的方式发生变化
vue是采用集中式管理组件依赖的共享数据的一个工具,可以解决不同组件数据共享问题
1.安装依赖
npm install vuex --save
在入口文件 main.js 中写入以下代码
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'
Vue.use(Vuex) //完成Vuex 的全局注册,实际上是调用了Vuex 里面的一个install 方法
// 实例化Vuex的store,实际上所有的state mutations actions 都存于store
const store = new Vuex.Store()
//把store挂在到vue实例上
new Vue({
render:h => h(App),
store
}).$mount('#app')
state是放置左右公共状态的属性,如果有一个公共状态的数据,你只需要定义在state对象中
// 初始化vuex对象
const store = new Vuex.Store({
state:{
count:0
}
})
方式一:插值表达式
组件中可以使用this. $store 获取到vuex 中的store对象实例
<div id="app"> state的数据:{{$store.state.count}} </div>
方式二:计算属性
将state属性定义在计算属性中
computed:{
count(){
return this.$store.state.count
}
}
方式三:辅助函数 mapState
mapState 是辅助函数,帮助我们把store中的数据映射到组件的计算属性中,是一种方便用法
<template>
<div id="app">
<div>使用mapState获取到state的数据:</div>
<div>{{count}}</div>
</div>
</template>
导入mapState
<script>
import { mapState } from 'vuex'
export default {
computed:{
// 采用数组形式引入state属性
// 利用延展计算符将导出的状态映射给计算属性
...mapState(['count']),
//上面的写法等价于下面的写法
count(){
return this.$store.state.count
}
}
}
</script>
state数据的修改只能通过 mutations ,mutations 必须是同步更新
mutatons 是一个对象,对象中存放修改state的方法
const store = new Vuex.Store({
state:{
count:0
}
// 定义mutatons
mutations:{
// 定义addCount 方法
// 方法里第一个参数是当前store的state属性
// 方法里第二个参数是运输参数,调用mutations 的时候,可以传递参数,传递载荷
addCount(state,payload){
state.count += payload
}
})
方式一:组件中使用 this.$store.commit
<template>
<div id="app">
<button @click="addCount">+10</button>
</div>
</template>
<script>
export default {
methods:{
addCount(){
// 调用store中的mutations
this.$store.commit('addCount',10)
}
}
}
</script>
方式二:使用mapMutations
<template>
<div id="app">
<!-- 如果这里只写方法名addCount,默认方法第一个参数是事件参数对象 event,所以要主动传一个参数进去 -->
<button @click="addCount(10)">+10</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
methods:{
...mapMutations(['addCount'])
}
}
</script>
actions 负责进行异步操作
//实例化vuex的store。实际上所有的state actions mutactions 都存在于store
const store = new Vuex.Store({
// state 存放数据
state:{
name:'鱼鱼喵',
count:0
},
// actions 是一个对象,存放的是修改state的方法
mutations:{
addCount(state,payload){
state.count += payload
}
},
// actions 也是一个对象,存放的也是方法,异步和同步均可编写
actions:{
// actions 第一个参数 context =》等同于this.$store 运行的store实例
// 可以给action方法传值
getAsyncCount(context,params){
setTimeout(()=>{
// 一秒钟之后去修改state
context.commit('addCount',params)
},1000)
}
}
})
方式一:通过 dispatch 去派发
<template>
<div id="app">
<button @click="addAsyncCount">异步调用actions</button>
</div>
</template>
<script>
export default {
methods:{
addAsyncCount(){
// 传参调用
this.$store.dispatch('getAsyncCount',100)
}
}
}
</script>
方式二:通过 mapActions 辅助函数
<template>
<div id="app">
<button @click="getAsyncCount(100)">异步调用actions</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods:{
...mapActions(['getAsyncCount'])
}
}
</script>
除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到 getters.getters类似于vue中的 computed 计算属性
例如,state中定义了一个 1-10 的 list 数组
state:{
list:[1,2,3,4,5,6,7,8,9,10]
}
组件中,需要显示所有大于5的数据,需要list在组件中进行再进一步的处理,getters可以帮助我们实现它
const store = new Vuex.Store({
// ...
// ...
getters:{
// getters 接收 state 作为其第一个参数
// getters 必须要有返回值 return
filterList:function(state){
return state.list.filter(item=> item > 5)
}
// 简写
// filterList:state => state.list.filter(item => item > 5)
}
})
方式一: $store
template
<template>
<div id="app">
<div>{{$store.getters.filterList}}</div>
</div>
</template>
方式二:mapGetters 辅助函数
<template>
<div id="app">
<div>{{filterList}}</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed:{
...mapGetters(['filterList'])
}
}
</script>
由于使用单一状态树,应用所有的状态会集中到一个比较大的对象,当应用变得非常复杂时,store对象就有可能变得非常臃肿。也就是说,如果把所有的状态都放在state中,当项目变得越来越大的时候,vuex会变得越来越难以维护。因此,又有了vuex的模块化
const store = new Vuex.Store({
// ...
// ...
// 模块
modules:{
// 模块一
user:{
state:{
token:123
}
},
// 模块二
setting:{
state:{
name:'vue实例'
}
}
}
})
方式一:$store.state.子模块名称.属性 的方式来获取
<template>
<div>
<!-- 要获取模块中的数据,不能直接.state来获取,而需要先获取子模块的名称。获取到子模块名称之后也不需要再.state -->
<!-- 错误写法一 -->
<!-- <div>用户的token:{{$store.state.token}}</div> -->
<!-- 错误写法二 -->
<!-- <div>用户的token:{{$store.state.user.state.token}}</div> -->
<!-- 正确写法 -->
<div>用户的token:{{$store.state.user.token}}</div>
<div>用户的token:{{$store.state.setting.name}}</div>
</div>
</template>
方式二:通过外层的 getters(总的getters)来获取
const store = new Vuex.Store({
// ...
// ...
// 模块
modules:{
// 模块一
user:{
state:{
token:123
}
},
// 模块二
setting:{
state:{
name:'vue实例'
}
}
}
getters:{
token:state => state.user.token,
name:state => state.setting.name // 使用一个总getters向外暴露子模块的属性
}
})
调用
<template>
<div>
<div>使用辅助属性:</div>
<div>{{token}}</div>
<div>{{name}}</div>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
computed:{
...mapGetters(['token','name'])
}
}
</script>
默认情况下,模块内部的action。mutation 和getters 是注册在全局命名空间的,这样使得多个模块能够对同一mutation 或action 做出相应。
换言之,上面的user模块还是setting模块,它的action、mutations 和 getters 其实并没有区分,都可以直接通过全局的方式调用
定义模块中的mutations
const store = new Vuex.Store({
// ...
// ...
// 模块
modules:{
// 模块一
user:{
state:{
token:123
},
mutations:{
// 此时的state 是模块中的state
updateToken(state){
state.token = 56789
}
}
},
// 模块二
setting:{
state:{
name:'vue实例'
}
}
}
})
调用模块中的mutations
<template>
<div>
<button @click="updateToken">调用模块中的mutations</button>
</div>
</template>
<script>
import {mapMutations} from 'vuex'
export default {
methods:{
...mapMutations(['updateToken'])
}
}
</script>
由此可见,子模块的mutations被暴露到了全局,子模块里面定义了多少方法,全局都可以轻而易举的拿到
但是,如果我们想保证模块内部的高封闭性,我们可以使用 namespaced 来进行设置
const store = new Vuex.Store({
// ...
// ...
// 模块
modules:{
// 模块一
user:{
namespaced:true,
state:{
token:123
},
mutations:{
// 此时的state 是模块中的state
updateToken(state){
state.token = 56789
}
}
},
// 模块二
setting:{
state:{
name:'vue实例'
}
}
}
})
给子模块 user 加了 namespaced:true 这个属性之后,就不能再按照前面的方法来调用mutations了
如果还按照上面的的方法来调用,则会报以下这个错误
所以,给子模块 user 加了 namespaced:true 这个属性之后,应该如何调用 mutations 呢?
方式一:带上模块的属性名路径
<template>
<div>
<div>给子模块user加上 namespaced:true 属性之后调用mutations的方法</div>
<button @click="test">修改token</button>
</div>
</template>
<script>
import {mapMutations} from 'vuex'
export default {
methods:{
//调用局部的 mapMutations
// 方法一:
// 给子模块user加上 namespaced:true 属性之后调用mutations的方法
...mapMutations(['user/updateToken']), // 引入全局的mutations
test(){
this['user/updateToken']() //调用子模块的方法
}
}
}
</script>
方式二:createNamespacedHelpers 创建给予某个命名空间辅助函数
<template>
<div>
<div>使用辅助属性:</div>
<div>{{token}}</div>
<div>{{name}}</div>
<!-- <div>给子模块user加上 namespaced:true 属性之后调用mutations的方法一</div> -->
<!-- <button @click="test">修改token</button> -->
<div>给子模块user加上 namespaced:true 属性之后调用mutations的方法二</div>
<button @click="updateToken">修改token</button>
</div>
</template>
<script>
import {mapGetters,createNamespacedHelpers} from 'vuex'
const { mapMutations} = createNamespacedHelpers('user')
export default {
computed:{
...mapGetters(['token','name'])
},
methods:{
//调用局部的 mapMutations
// 方法一:
// 给子模块user加上 namespaced:true 属性之后调用mutations的方法
// ...mapMutations(['user/updateToken']), // 引入全局的mutations
// test(){
// this['user/updateToken']() //调用子模块的方法
// }
// 方法二:
...mapMutations(['updateToken'])
}
}
</script>
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。