1.为什么要学习vuex
vuex是一种对状态做到响应式管理的工具
<script>
const objShare = {
name: 'guodong'
}
Vue.prototype.objShare= objShare
Vue.component('cpn1',{
// this.objShare.name) 在这里拿到
})
Vue.component('cpn2',{
// this.objShare.name)
})
new Vew({
el:'#app'
})
</script>
这里定义一个objShare来管理共享的变量,因为所有的组件都是继承自Vue.prototype,所以所有的组件都可以拿到这个。但此时的变量不是响应式的,也就是说如果cpn2修改了name,此时cpn1里面的name是不跟着改的,因为它并没有放到响应式系统里。
2.管理什么样的状态
1)比如用户的登录状态,用户的名称、头像、地理位置信息等
2)比如商品的收藏和购物车
3.单页面的状态管理
代码:
<template>
<div id="app">
<h2>{{msg}}</h2>
<span>{count}</span>
<button @click="count++">+</button>
<button @click="count--">-</button>
</div>
</template>
<script>
export default {
name: 'app',
components: {
},
data () {
return {
msg: '我是App组件',
count: 0
}
}
}
</script>
<style>
</style>
这里的data就相当于这个组件的state,{{count}}就相当于view,@click就是action
4.vuex的环境配置
1)创建一个store的文件夹,再 创建一个index.js
2)导入vuex,并且安装
import Vuex from 'vuex'
import Vue from 'vue'
/**
* 1.安装插件
*/
Vue.use(Vuex)
3)创建变量,并且导出(注意:这里new的是Store对象)
const store = new Vuex.Store({
state: {},
mutations: {},
actions: {},
getters: {},
modules: {}
})
export default store
4)在main.js中导入 ,并且挂载到vue实例中
import store from './store'
import './plugins/element.js'
Vue.config.productionTip = false
new Vue({
store,
router,
render: h => h(App)
}).$mount('#app')
挂载到vue实例中之后,就相当于Vue.prototype. s t o r e = s t o r e , 到 时 候 在 所 有 的 组 件 中 就 可 以 通 过 store=store,到时候在所有的组件中就可以通过 store=store,到时候在所有的组件中就可以通过store拿到index.js中定义的store
vuex的机制
–可以看到在引用vuex中的内容是,可以直接的进行插值,但不推荐直接的修改vuex中的内容,因为到时候可能会有很多的组件要修改vuex的内容,如果中间有一个改错了,就不知道是哪一个组件改错,就不能监听到,所以这里就需要devtools,devtools是vue开发的一个浏览器插件,它可以用来记录每一次状态改变。
=而action是用来进行异步操作的,因为mutation是不能监听到异步操作的
5.安装devtools的插件:
插件包在h://devtools中
在mutation中定义改变属性的方法:
const store = new Vuex.Store({
state: {
counter: 100
},
mutations: {
increase (state) {
state.counter++
},
decrease (state) {
state.counter--
}
},
actions: {},
getters: {},
modules: {}
})
其中每一个方法都会默认的传递一个参数state,通过state拿到定义的数据
之后在使用的时候是需要调用this.store.commit(‘方法名’),是用来提交一个方法
methods: {
btnClick1 () {
this.$store.commit('increase')
},
btnClick2 () {
this.$store.commit('decrease')
}
}
6.state的单一状态树:
如果状态保存到多个store对象中,那么之后的管理和维护都会变得很困难,所以在使用的时候,我们只用一个store来存储所有的状态。
7.getters的基本使用:
此时我们是需要从getters里面去获取一些变异后的状态,
1)和mutations中的方法一样,getters里的方法也是会自动的有一个state参数,
之后在使用的时候是用 $store.getters.属性名
getters: {
powerCounter (state) {
return state.counter * state.counter
},
ageMore20 (state) {
return state.students.filter(item => item.age > 20)
}
},
{{$store.getters.ageMore20}}
{{$store.getters.powerCounter}}
这里和组件中的computed方法很像
2)getters作为参数和传递参数
+++++++++作为参数:(当能用到前面定义的getters属性时使用)
ageMore20Length (state, getters) {
return getters.ageMore20.length
}
+++++++++传递参数:如果希望传递参数,只能让getters方法本身返回一个函数
moreAgeStu (state) {
return function (age) {
return state.students.filter(item => {
return item.age > age
})
}
}
{{$store.getters.moreAgeStu(25)}}
因为这里$store.getters.moreAgeStu返回的是一个函数,所以他本身后面就就可以传递参数
8.Mutation传递参数:
+++当只有一个参数的时候
this.$store.commit('increaseCount', count)
increaseCount (state, count) {
state.counter += count
}
+++当需要传递的参数有很多时,直接传递一个对象
btnClick4 () {
const stu = {
id: 4,
name: 'alan',
age: 78
}
this.$store.commit('increaseStudent', stu)
}
increaseStudent (state, stu) {
state.students.push(stu)
}
9.mutation的提交风格:
btnClick3 (count) {
// this.$store.commit('increaseCount', count)
this.$store.commit({
type: 'increaseCount',
count
})
},
第一种风格
increaseCount (state, count) {
state.counter += count
},
第二种风格
increaseCount (state, payload) {
state.counter += payload.count
},
其中第二种风格第二个参数传递的是一个对象,payload是负载的意思,
10.mutation的响应规则:
Vuex中的store中的state是响应式的,当state中的数据发生变化时,Vue组件会自动的更新。
这就要求我们要遵守一些规则:
1)提前在store中初始化属性,
2)当给state中的对象添加新属性时,使用下面的方式:
使用Vue.set(obj,‘objProp’,‘newValue’)
这里的set方法既可以用来处理数组也可以用来处理对象,唯一的区别是set数组的话,第二个参数是整形的索引值,set对象的话,第二个参数是对象属性的字符串形式。
3)删除一个属性的时候:
Vue.delect(obj,‘objProp’)
updataStu (state) {
Vue.set(state.students[0], 'email', '2291230083@qq.com')
},
delStu (state) {
Vue.delete(state.students[0], 'name')
}
11.vuex-mutation的类型常量
目的是为了更加的规范,也不容易出错
1)首先是创建一个mutation-styles.js文件
export const INCREMENT = 'increment'
2)之后在组件内导入
this.$store.commit(INCREMENT)
此时commit里面传入的就是一个常量了
3)相应的在vuex的index.js中导入,
[INCREMENT] (state) {
state.counter++
},
11.action方法的使用
原因:在mutation中,当我们使用devtools时,devtools可以帮助我们捕捉mutation的快照,但当我们执行异步操作时,devtools就不能很好的追踪到这个操作是什么时候完成的。
当需要用异步操作时,我们需要放到action里面
1)this.$store.dispatch('aupdataStu')
----先是要dispatch到action方法中,
2)
actions: {
aupdataStu (context) {
setTimeout(() => {
context.commit('updataStu')
}, 1000)
}
},
注意:这里区别于getters和mutations中的方法是,actions里方法的参数是context,而不是state,context拿到的是store对象
因为在actions里面并不是直接的操作state值,对state进行修改的操作还是要放在mutations里面,只不过这里是多一步
3)
updataStu (state) {
Vue.set(state.students[0], 'email', '2291230083@qq.com')
},
----------------如果此时我有个需求是需要在修改信息成功之后,然后提示修改信息成功,此时我可以让dipatch方法携带一个对象,对象中包含着需要传递的参数,还有一个回调函数
btnClick5 () {
this.$store.dispatch('aupdataStu', {
message: '我是携带的信息',
success () {
console.log('修改成功')
}
})
}
之后在commit之后,再调用success回调
aupdataStu (context, payload) {
setTimeout(() => {
context.commit('updataStu')
console.log(payload.message)
payload.success()
}, 1000)
}
**这里有一个启发:现在对象就可以视为是一个存储数据的结构,它里面可以存放各种数据,当我们需要各种参数的时候,就可以把这些都放在一个对象里进行传递 **
但是上面这种方式不够优雅
我们可以使用promise来封装异步操作,之后再调用then来回调
actions: {
aupdataStu (context) {
new Promise((resolve, reject) => {
setTimeout(() => {
context.commit('updataStu')
resolve('信息修改成功')
}, 1000)
}).then((data) => {
console.log(data)
})
}
}
更优雅的方式
这里是让dispatch返回的是一个promise对象,之后再调用promise对象的回调函数。
actions: {
aupdataStu (context, payload) {
return new Promise((resolve, reject) => {
setTimeout(() => {
context.commit('updataStu')
console.log(payload)
resolve('111')
}, 1000)
})
}
}
btnClick5 () {
this.$store.dispatch('aupdataStu', '携带的信息').then(res => {
console.log('信息修改成功')
console.log(res)
})
}
12.modules的使用
1.使用modules里面的state
modules: {
a: moudleA
}
const moudleA = {
state: {
name: 'zhangsan'
},
mutations: {},
getters: {},
actions: {}
}
这里在去取module中name的时候,它会把modules中的a放在state中,此时a中没有state、mutations等这些属性了,会把state中的属性取出来当作自己的属性。所以我们在取得时候,是去state中去拿,而且此时也不需要再写a.state.name了,直接就是a.name.
<h2>{{$store.state.a.name}}</h2>
2.使用modules中的mutations,它在编译得时候是会把moudules的mutation中的方法和外面的方法都放在外面的mutations中
使用起来和之前一样。
3.使用modules中的getters,三种方式
getters: {
fullName (state) {
return state.name + '111'
},
fullName1 (state, getters) {
return getters.fullName + '222'
},
fullName2 (state, getters, rootState) {
return getters.fullName1 + rootState.counter
}
},
其中rootState是外面state的引用,目的是可以拿到外面state的属性
<h2>{{$store.getters.fullName}}</h2>
<h2>{{$store.getters.fullName1}}</h2>
<h2>{{$store.getters.fullName2}}</h2>
4.使用modules中的actions
actions: {
achangeName (context) {
setTimeout(() => {
context.commit('changeName')
}, 1000)
}
}
注意:这里的context就不再是$store,也就是说modules中的actions方法只能调用modules中的mutations方法。
其中这里的context包含很多的属性
action {
incrementSum({state, rootstate, commit}) {
if((state.count + rootstate.count)%2 == 0) {
commit('increment')
}
}
}
这里的incrementSum参数里面是对象的解构赋值,相当于是:
const context = {
state:{},
rootstate:{},
commit:{}
}
const state = context.state
const rootstate = context.rootstate
const commit = context.commit
const {state, rootstate, commit} = context
13.store包内文件的结构:
如果把mutations、getters、actions都放在一个store中会非常的不方便维护:
所以就抽离出来,再导入导出,唯一state不用再放到外面
import Vuex from 'vuex'
import Vue from 'vue'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'
/**
* 1.安装插件
*/
Vue.use(Vuex)
const state = {
counter: 100,
students: [
{
id: 1,
name: 'guodong',
age: 22
},
{
id: 2,
name: 'xiaozhang',
age: 19
},
{
id: 3,
name: 'xiaohong',
age: 30
}
]
}
// 创建对象
const store = new Vuex.Store({
state,
mutations,
actions,
getters,
modules: {
a: moduleA
}
})
export default store