getter相当于vuex里面的计算属性。
在vue组件中如果我们要触发一个全局的状态更新呢的话,中间其实还缺少一条线。如果我们的操作不具有异步操作的话,可以不走action,可以直接在vue组件中通过cmmitMutations来提交一个状态的改变。然后接着走下面的流程。
当我们在组件中需要自改vuex中的state状态值的时候,我们不可以在组件中直接修改这个值,而是需要commit提交一个mutation或者dispatch一个action,来走这么一个流程,这么看起来貌似很复杂和多余,这种操作是为了更清楚的帮我们梳理我们数据的改变,能够提供一个清晰的数据流,
实战
在mutations创建对象,然后把这个对象导出去。
index.js内引进来,然后创建实例的时候把他添加进去。
根级别的state有个appName
在这里我们使用了这个appName,它是一个计算属性,返回的是store中的appName
修改这个state的值,先在上面定义一个按钮
提示注册属性被指定了,但是它没有setter。
类似于这种get和set的写法,这只是做一个简单的示范
appName: { set: function (newValue) { this.inputValue = newValue + 'sd' }, get: function () { return this.inputValue + 'sdfsdf' } },
参数1就是通过那个方法名修改这个值
方法是在mutation中定义的。SET_APP_NAME
方法有个参数是state,就是同级别的state对象,
第二个参数vuex文档中叫做载荷,其实他就是参数值。如果是多个值的话params就是对象的形式,因为我们这里是一个值可以直接用params
commit的第一个参数就是我们要提交的名称
第二个参数就是要赋的新值
handleChangeAppName () { // this.appName = 'newAppName' this.$store.commit('SET_APP_NAME', 'newAppName') }
修改多个参数
这里就是一个对象的形式
handleChangeAppName () { // this.appName = 'newAppName' this.$store.commit('SET_APP_NAME', { appName: 'newAppName' }) }
const mutations = { SET_APP_NAME (state, params) { state.appName = params.appName } }
直接一个参数,对象的写法
type就是mutations内的名称
this.$store.commit({ type: 'SET_APP_NAME', appName: 'newAppName' })
params就是一个对象了 ,还是要通过params.appName
添加新的state值
想给state动态的添加appVersion这个属性
appVersion现在是没有的。后面想让他有这个值。
引入vue,使用vue的set方法,给state对象
然后使用这个appVersion
如果这里不用vue的set方法的话,直接修改state的appVersion属性
没有效果
说明在这里没有更新视图,这是vue中提到的响应式的原则,
如果一开始没有在state中定义,在创建实例的时候 是不会被添加get和set方法的,
那么视图就不会响应式的去更新。那么就需要使用vue.set把这个新的值添加到state对象上,同时它会给你添加get和set方法,同时会触发视图更新
mapMutations
注意:...mapMutations这个是methods里面定义的
这里改成直接用params
同时也可以写成对象的形式
模块中的mutation
上面新添加一个按钮
这里没有写模块名称,因为vuex会把模块中的和通用级别的,通通注册在全局当中,你只需要把它当做根级别的定义的get和mutation一样调用即可。
如果你想给他一个密闭的环境就设置namespaced
mutation中修改的值是通过接口获取的
获取接口中的操作呢,ajax请求是一个异步的操作。这个逻辑 是不能放在mutation中操作的。mutation只能做一些同步的操作。
如果有一些异步的操作 ,请求接口的数据再去修改state的值 怎么做?就会需要用到下面课要讲的action
Action
修改根级别的appName。这种写法是ES6的解构赋值
相当于这种写法,接收一个对象,然后获取对象中的commit
模拟一个异步的操作。假设getAppName是一个接口请求。
接口定义在api文件夹下的app.js
引用的简写形式
创建app.js
定义个promise对象,然后用settimeOut模拟一个http的延迟请求。
这里调用异步操作,打印这个结果看下
先注释掉
在这里提交一个action。先引入工具方法mapAction
调用这个方法
如果有catch就输出这个错误
提交修改appName
这里改成单个参数
还可以使用ES6的解构赋值
const { code, info: { appName } } = res commit('SET_APP_NAME', appName)
code没有用到这里就删掉
const { info: { appName } } = res commit('SET_APP_NAME', appName)
还可以使用store实例上的方法触发这个action,使用this.$store.dispatch(); 使用dispatch这个方法来触发action。参数载荷,可以以为对象 {}的形式,如果是一个值的话,就直接用'123'
这句话注释掉。
使用ES8的async来处理异步的问题。
这里使用了promise来处理逻辑。这种是类似于回调的形式。看起来并不是非常的友好
await等待一个异步函数执行,当它执行完成后,它会往下走,
async getAppName ({ commit }) { const { info: { appName } } = await getAppName() commit('SET_APP_NAME', appName) }
刚才方法名写错了
async处理异常 try catch的形式
async updateAppName ({ commit }) { try { const { info: { appName } } = await getAppName() commit('SET_APP_NAME', appName) } catch (error) { console.log(error) } }
module模块
当项目非常大的时候,store就会变的非常的臃肿,拆成模块管理比较清晰。每一个模块是一个独立的store
user下面还可以包含模块,拆分更细的模块。
如果user加上了命名空间那么这里调用的时候,也需要加上
如果模块里面套模块,这里就这么写
模块中用action
这种方式提交action
action中有另外的方法,可以在上面调用,用dispatch
store实例动态的注册一个模块。
动态的注册模块
第一个参数是模块名称,后面是一个对象,
注册一个todoList
如果有state.todo。那么就用state.todo.todoList.没有的话就是个空数组
todoList: state => state.todo ? state.todo.todoList : []
在上面做个循环
模块添加模块。给user模块添加一个子模块叫做todo
registerModule () { this.$store.registerModule(['user', 'todo'], { state: { todoList: [ '学习mutations', '学习actions' ] } }) }
把todo模块注册在user模块里 。
todoList: state => state.user.todo ? state.user.todo.todoList : []
结束