本文共 7961 字,大约阅读时间需要 26 分钟。
本人是个新手,写下博客用于自我复习、自我总结。 如有错误之处,请各位大佬指出。 学习资料来源于:尚硅谷
vuex 是什么
现在先写个vue版的代码,之后来看看vuex会是什么样。
main.js
/* 入口JS */import Vue from 'vue'import App from './App.vue'/* eslint-disable no-new */new Vue({ el: '#app', components: { App}, // 映射组件标签 template: '' // 指定需要渲染到页面的模板})
App.vue
click {
{count}} times, count is { {evenOrOdd}}
状态自管理应用
template
部分)多组件共享状态的问题
const state = { xxx: initValue}
const mutations = { yyy (state, { data1}) { // 更新 state 的某个属性 }}
const actions = { zzz ({ commit, state}, data1) { commit('yyy', { data1}) }}
const getters = { mmm (state) { return ... }}
export default new Vuex.Store({ state, mutations, actions, getters})
import { mapState, mapGetters, mapActions} from 'vuex' export default { computed: { ...mapState(['xxx']), ...mapGetters(['mmm']), } methods: mapActions(['zzz'])}{ { xxx}} { { mmm}} @click="zzz(data)"
import store from './store' new Vue({ store})
项目结构:(对最开始的代码进行修改)
首先安装 npm i --save vuex
store.js
/*vuex最核心的管理对象store */import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)/*相当于data对象的状态对象 */const state = { count: 0 // 指定初始化数据}/*包含了n个直接更新状态的方法的对象 */const mutations = { INCREMENT (state) { state.count++ }, DECREMENT (state) { state.count-- }}/*包含了n个间接更新状态的方法的对象 */const actions = { //增加的action increment ({ commit}) { // 提交一个mutation请求 commit('INCREMENT') }, //减少的action decrement ({ commit}) { // 提交一个mutation请求 commit('DECREMENT') }, //带条件的action incrementIfOdd ({ commit, state}) { if(state.count%2===1) { // 提交一个mutation请求 commit('INCREMENT') } }, //异步的action incrementAsync ({ commit}) { //在action中直接就可以执行异步代码 setTimeout(() => { // 提交一个mutation请求 commit('INCREMENT') }, 1000) },}/*包含多个getter计算属性的对象 */const getters = { evenOrOdd (state) { // 当读取属性值时自动调用并返回属性值 return state.count%2===0 ? '偶数' : '奇数' }}/*向外暴露 store 对象 */export default new Vuex.Store({ state, //状态对象 mutations, //包含多个更新state函数的对象 actions, //包含多个对应事件回调函数的对象 getters //包含多个getter计算属性函数的对象})
main.js
/*入口js */import Vue from 'vue'import Counter from './Counter.vue'import store from './store'new Vue({ el: '#app', components: { Counter }, template: '', store // 注册vuex的store: 所有组件对象都多一个属性$store})
Counter1.vue(原始版本,Counter为对Counter1的改进版,在之后)
click {
{count}} times, count is { {evenOrOdd}}
它的整体思路就是:
首先建一个store.js,用来存放Vuex相关内容,在其中: ①引入Vueximport Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)
②向外暴露store对象(基本上每次都会暴露这几个对象)
export default new Vuex.Store({ state, //状态对象 mutations, //包含多个更新state函数的对象 actions, //包含多个对应事件回调函数的对象 getters //包含多个getter计算属性函数的对象})
③格式比较固定,暴露之后,肯定要对以上所有对象进行实现:
/*相当于data对象的状态对象 */const state = { //初始化数据 count: 0 }/*包含了n个直接更新状态的方法的对象 */const mutations = { INCREMENT (state) { state.count++ }}/*包含了n个间接更新状态的方法的对象 */const actions = { increment ({ commit}) { // 提交一个mutation请求 commit('INCREMENT') }, incrementIfOdd ({ commit, state}) { if(state.count%2===1) { // 提交一个mutation请求 commit('INCREMENT') } }}/*包含多个getter计算属性的对象 */const getters = { evenOrOdd (state) { // 当读取属性值时自动调用并返回属性值 return state.count%2===0 ? '偶数' : '奇数' }}
那么这里面最基本的用法就是,先在组件中调用actions中的方法,然后在actions中去调用mutations中的方法,用来直接对state数据进行改变(更新状态)。
全部都弄好后,即然要在组件中使用,就要想办法创建个store对象,即在main.js中:
①导入组件和storeimport Vue from 'vue'import Counter from './Counter.vue'import store from './store'
②注册vuex的store,这样一来所有组件对象都会多一个属性$store
,这样之后就能使用store中的方法了。
new Vue({ el: '#app', components: { Counter }, template: '', store // 注册vuex的store: 所有组件对象都多一个属性$store})
注册好之后,就要考虑如何去使用了,进入组件中。因为上面说到,我们在组件中调用actions中的方法,在actions中设置时会去帮我们调用mutations中的方法,所以在组件中,使用store对象目前只涉及到三种用法:
①this.$store.state.count
②this.$store.getters.evenOrOdd
③this.$store.dispatch('increment')
分别可以调用store对象中的state、getters和actions。注意调用actions用的是dispatch,这个看上面的图就发现了,规定用的就是dispatch。 这样一来就可以连接起每个部分了。
在上面还说到有个简化版,Counter.vue:
click {
{count}} times, count is { {evenOrOdd}}
因为store里的每个对象可能会有多个方法,我们一个一个去调用还是很麻烦的,现在就可以一次性全部导入。
首先要引入import {mapState, mapGetters, mapActions} from 'vuex'
,然后使用。分别为: ①...mapState([])
②...mapGetters([])
③...mapActions([])
注意这时候调用actions,可不是dispatch了。 最后再通过结构图理解一下:
vuex里有四个结构,state、mutations、actions、getters。 更新state的是mutations、用state进行计算的是getters。 操作mutations的是actions。 这四个都是对象。 state里面包含的数据原本是从vue组件中转移过来的。 而组件要想获取到state里的数据,有四种方式:$store.state
或 mapState()
$store.getters
或mapGetters()
在vue中对标签 / 按钮进行操作,分发事件,触发action调用,用到的就是dispatch()
或mapActions()
。action不能直接对数据进行操作,所以去请求mutation,用到的就是commit()
。这时候可能需要获取数据后再commit,所以就涉及到后台backend,用到的就是ajax请求,也就是说在vuex里可以直接进行异步操作。而到了mutation就可以直接更新状态。mutation里还有个开发工具devtool,专门用来监视mutation。
在最后再说几个问题:在正常项目中,vuex的四个结构,即store.js中的四个对象包含的数据 / 方法可能会比较多,都放在store.js中,不太好处理(当然都放在一起也行,还是需要看习惯)。所以,我们可以把它们分开来存放。
index.js:/*vuex核心管理模块store对象 */import Vue from 'vue'import Vuex from 'vuex'import state from './state'import mutations from './mutations'import actions from './actions'import getters from './getters'Vue.use(Vuex)export default new Vuex.Store({ state, mutations, actions, getters})
state.js
/*状态对象模块 */export default { todos: []}
getters.js
/*包含n个基于state的getter计算属性方法的对象模块 */export default { // 总数量 totalSize (state) { return state.todos.length }}
actions.js
/*包含n个用于间接更新状态的方法的对象模块 */import { ADD_TODO, DELETE_TODO} from './mutation-types'export default { addTodo ({ commit}, todo) { // 提交一个comutation请求 commit(ADD_TODO, { todo}) // 传递给mutation的是一个包含数据的对象 }, deleteTodo ({ commit}, index) { commit(DELETE_TODO, { index}) }}
mutation-types.js
/*包含n个mutation名称常量 */export const ADD_TODO = 'add_todo' // 添加todoexport const DELETE_TODO = 'delete_todo' // 删除todo
mutations.js
/*包含n个用于直接更新状态的方法的对象模块 */import { ADD_TODO, DELETE_TODO} from './mutation-types'export default { [ADD_TODO] (state, { todo}) { // 方法名不是ADD_TODO, 而是add_todo state.todos.unshift(todo) }, [DELETE_TODO] (state, { index}) { state.todos.splice(index, 1) }}
还有就是,我们在main.js里,之前我们做的操作,需要映射组件标签+指定渲染到页面的模板:
/*入口JS */import Vue from 'vue'import App from './App.vue'import store from './store'/* eslint-disable no-new */new Vue({ el: '#app', components: { App}, // 映射组件标签 template: '', // 指定需要渲染到页面的模板 store})
有一个简便写法:
/*入口JS */import Vue from 'vue'import App from './App.vue'import store from './store'/* eslint-disable no-new */new Vue({ el: '#app', render: h => h(App), //简化 store })
这个render是一个渲染函数,它完整写是这样的:
render: function(createElement){ return createElement(App) //返回的是},
就相当于它会返回一个App标签,然后插入到el里就可以了。
转载地址:http://dlyki.baihongyu.com/