赞
踩
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
vuex 安装
npm i vuex
vuex是存储组件数据的集中式的仓库(如何优雅的读写仓库中的数据)
state:仓库内存数据的配置
getters:仓库内的计算属性
action:操作数据的工具
mutation:操作数据的工具
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
创建文件store,文件store.js 引入并暴露
在一个模块化的打包系统中,您必须显式地通过 Vue.use()
来安装 Vuex:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
上述步骤必须在创建仓库之前完成!
Vuex 通过new Vuex.Store({配置对象})来新建一个仓库
仓库的所有数据保存在配置对象的state属性中
// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)
// 在src目录下新建store目录 再新建index.js文件来存放仓库
import Vuex from "vuex"
const store = new Vuex.Store({
state: {
count: 0
}
})
export default store
Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex)):main.js
import store from './store'
new Vue({
store, //import一个文件,该文件内的代码会被执行,暴露出来的内容也会被拿到
})
由于上一步把 store 的实例注入了所有的子组件 所以任何组件都可以通过其自身的$store来访问仓库 在component新建count.vue
<template> <div> {{count}} // 没有响应式 //{{$store.state.count}} 有响应式 若被input直接使用,会出现脏数据 </div> </template> <script type="text/ecmascript-6"> export default { name: "App", data(){ return { count:this.$store.state.count } } } </script>
注意:
computed:{
count:{
get() {
return this.$store.state.count
},
set(newCount) {
console.log(newCount)
}
}
}
在整个组价的改造过程中,我们发现是需要修改计数器的值,
当我们通过 this.$store.state.count++
这种方式去修改store中的数据时发现仓库数据变了
可是界面上的数据没有更新. 在对仓库数据进行修改时 我们必须遵守 Vue 的响应规则
开启严格模式,仅需在创建 store 的时候传入 strict: true
:
const store = new Vuex.Store({
// ...
strict: true
})
在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。
这能保证所有的状态变更都能被调试工具跟踪到。
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
Vuex 中的 mutation 非常类似于事件:
① 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
② 这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
const store = new Vuex.Store({
strict: true,
state:{
count:0
}, //修改仓库数据的工具
mutations:{
add(state){
state.count++
},
}
})
export default store
不能直接调用一个 mutation handler。
这个选项更像是事件注册:“当触发一个类型为 increment
的 mutation 时,调用此函数。”
要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法:
store.commit('add')
你可以向 store.commit
传入额外的参数,即 mutation 的 载荷(payload):
mutations: {
add (state, step) {
state.count += step
}
}
methods:{
add() { this.$store.commit("add",2)}
}
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:
mutations:{
add(state,{step,msg}) {
state.count += step
}
}
add() {this.$store.commit("add",{step:2,msg:"hello"})}
提交 mutation 的另一种方式是直接使用包含 type
属性的对象:
add() {
this.$store.commit({
type:"add",
step:2,
msg:"hello"
})
}
当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:
mutations:{
add(state,{step,msg}) {
state.count += step
}
既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
最好提前在你的 store 中初始化好所有所需属性。
当需要在对象上添加新属性时,你应该
Vue.set(obj, 'newProp', 123)
注意:
Mutation 必须是同步函数
vue 的 devtool 中会记录每一条 mutation 日志。如果mutation中存在异步代码,会导致devtools中的记录变的混乱不可维护, 当我们在mutation中书写异步代码时,严格模式下vue会提出警告,非严格模式下vue不会做出任何反应
Action 类似于 mutation,不同在于:
让我们来注册一个简单的 action:
//进行同步注册
mutations:{
asyncAdd(state,step) {
state.count += step
}
},
//再异步修改仓库数据
actions:{
asyncAdd(store,step){
//store: 仓库对象
setTimeout(()=>{
store.commit("asyncAdd",step)
},2000)
}
},
Action 通过 store.dispatch
方法触发使用:
<button @click.stop="asyncAdd">aysnc btn(2000)</button> //会有冒泡,因此用stop阻止
methods:{
asyncAdd(){
// this.$store.commit("asyncAdd",3)
this.$store.dispatch("asyncAdd",3)
}
}
Actions 支持同样的载荷方式和对象方式进行分发:
有时候我们需要从 store 中的 state 中派生出一些状态.如果有多个组件需要用到此状态
就可以在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,
getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
Getter 接受 state 作为其第一个参数:
// 仓库文件
getters: {
flag(state) {
return state.count%2===0 ? "偶":"奇"
}
},
Getter 会暴露为 store.getters
对象,你可以以属性的形式访问这些值
computed: {
flag(){
return this.$store.getters.flag
}
}
import { mapState,mapGetters,mapMutations } from 'vuex'
简化业务组件的开发
- mapState({}) 或者 mapState([])
- mapGetters({}) 或者 mapGetters([])
- mapMutations({}) 或者 mapMutations([])
- mapActions({}) 或者 mapActions([])
- vuex中的state 我们在组件中使用时通常需要有对应的computed
- vuex中的getters 我们在组件中使用时通常需要有对应的computed
- vuex中的mutations 我们在组件中使用时通常需要有对应的methods
- vuex中的actions 我们在组件中使用时通常需要有对应的methods
mapState(["count" ]) ==> 返回 {count(){return this.$store.state.count}}
mapState({
myCount:"count" ==> 返回 {myCount(){return this.$store.state.count}}
})
...mapState(["count"])
mapGetters(["flag"]) ==> return this.$store.getters.flag
...mapGetters([flag]) //...表示把里面里面的数据展开显示
...mapActions(["add","asyncAdd"])
传参可以在点击事件之后进行
<div class="count" @click="add(2)">
{{count}}
<button @click.stop="asyncAdd(3)">异步的函数</button>
</div>
1. 仓库内部的state getters配置都会转绑给仓库对象
2. Vue.prototype.$store : 代表的就是仓库对象
任意一个组件都可以通过 $store 这个属性来访问到仓库
3. 仓库中的数据也是响应式的
4. 仓库中的数据也不能直接在组件上读取;任意产生脏数据
我们应该使用计算属性来读取仓库中数据
同步修改:
组件上转发action
action内部提交mutation
mutation内部同步的修改数据
界面得到更新
异步修改:
组件上转发action
action内部处理异步逻辑;在异步完成时提交mutation
mutation内部同步的修改数据
界面得到更新
mapState,mapGetters, 结合 ...运算符在vue的computed配置中结合使用
computed:{
... mapState(["count"])
... mapGetters(["count"])
}
mapActions,mapMutations 结合 ...运算符在vue的methods配置中结合使用
methods:{
... mapMutations(["count"])
... mapActions(["count"])
}
传参: 在模板上使用方法时直接传参
mapState(["count"])
{
count:function(){
return this.$store.state.count
}
}
mapState({myCount:count})
{
myCount:function(){
return this.$store.state.count
}
}
mapActions(["add"])
{
add:function(payload){
this.$store.dispatch("add",payload)
}
}
mapActions({myAdd:add}})
{
myAdd:function(payload){
this.$store.dispatch("add",payload)
}
}
mapState([ ]),mapState([{}) :当前这种使用形式,默认读取总仓库中的数据
如何将仓库分模块使用
① 定义分仓库:
export default new Vuex.Store({
//vuex模块
modules:{
a
}
}
export default {
state:{test:"a模块中的test"},
getters:{},
mutations:{},
actions:{}
}
注册分仓库
② 如何读取总仓库的数据
mapState({key:()=>{}}); mapState中的参数是一个对象 {key:函数}
函数的返回值才是真正要被渲染的数据!
当前函数的参数是总仓库中的state
...mapState(["test"]),
③ 如何修改分仓库的数据
分仓库中的所有state数据是注册在当前模块下的;得通过 总仓库中的state.模块名.数据名 来访问
…mapState({组件上使用时的计算属性的名称:state=>state.模块名.数据名})
...mapState({testFromA:state=>state.a.test}),
④ 如何修改分仓库总仓库的数据
在总仓库中出现的所有 state都代表是总仓库自己的state
在分仓库中出现的所有 state都代表是分仓库自己的state
不管是总仓库中mutation,actions;getters 还是分仓库中的mutation,actions;getters 都是定义在全局的!
所以修改分仓库的数据 还是 按照总仓库的模式进行处理!
state:{
test:"总仓库中的test"
},
mutations:{
updateTest(state){
state.test = "总仓库中的 copy test"
}
},
actions:{
updateTest(store){
store.commit("updateTest")
}
},
//在分仓库中出现的所有 state都代表是分仓库自己的state export default { state:{ test:"a模块中的test" }, getters:{ getDataFromA(state){ return state.test+"-getters" } }, mutations:{ updateATest(state){ state.test = "a模块中的 copy test" } }, actions:{ updateATest(store){ store.commit("updateATest") } } }
注意:
什么 样的数据应该进仓库?
多组件共享的数据都要放仓库,请求相关的数据也要放仓库
store.js npm i vuex 配置 暴露 拆分组件 新建文件并往外暴露对象
main.js注册vuex配置
state.js 把所有(list search)data中的数据放入到这里 辅助函数
search.js username需要修改,辅助做不到,因此自己写(get set)在actios mutations中进行编写
flag的修改同username actions修改稿数据后记得触发(methods)
list.vue 总线不要了 发送请求在actions中,数据都在仓库中
在search中发送请求,点击search才有的数据
【】拿到的是变量,不是字符串
store.commit("updateATest")
}
}
}
**注意:** - mapState(["state中数据的名称"]);mapState({key:"state中数据的名称"}); - mapState中的参数是一个数组 或者 对象 {key:string}的时候 - 默认读取的都是总仓库中的数据; 什么 样的数据应该进仓库? 多组件共享的数据都要放仓库,请求相关的数据也要放仓库 # 11 小练习 store.js npm i vuex 配置 暴露 拆分组件 新建文件并往外暴露对象 main.js注册vuex配置 state.js 把所有(list search)data中的数据放入到这里 辅助函数 search.js username需要修改,辅助做不到,因此自己写(get set)在actios mutations中进行编写 flag的修改同username actions修改稿数据后记得触发(methods) list.vue 总线不要了 发送请求在actions中,数据都在仓库中 在search中发送请求,点击search才有的数据 【】拿到的是变量,不是字符串
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。