Vuex基本使用及进阶
一、下载vuex依赖
npm install vuex -S
二、启用vuex
在src文件下创建store文件夹,在里面新建一个index.js文件,在文件里书写以下代码
import Vue from 'vue'
import Vuex from 'vuex'
// 启用vuex
Vue.use(Vuex)
// 声明vuex实例对象,创建四个对象属性
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
getters: {}
})
三、注入store
在main.js文件中全局注入store实列对象
// 引入store实例对象
import store from '@/store/index'
// 将store注入到vue实列对象中
new Vue({
el: '#app',
store,
render: h => h(Counter)
})
四、vuex的使用
1、state的使用
用来存储数据的对象,对象中的数据可以在所有组件中使用
1.存储数据
const state = {
newData: 5
}
2.在其他组件中获取数据
this.$store.state.newData
// 例如:输出结果为5
<p>{{$store.state.newData}}</p>
3.获取state中多个数据
// 通过引入mapState辅助函数实现
import {mapState} from 'vuex'
注意mapState函数有两个方式赋值,需要结合计算属性
第一种是对象赋值
computed: mapState({
// 箭头函数让代码简练
count: state => state.count
// 传字符串参数可以等价于箭头函数: 'count' == state => state.count
countAlias: 'count'
})
案例演示:
// store>index.js
export default new Vuex.Store({
state: {
count: 1,
sum: 10,
add: 5
}
})
// state.vue
<script>
import {mapState} from 'vuex'
export default new Vue({
computed: mapState({
count: state => state.count,
sum: state => state.sum,
add: state => state.add
})
})
</script>
<template>
<div id="state">
<p>{{count}}</p> // 1
<p>{{sum}}</p> // 10
<p>{{add}}</p> // 5
</div>
</template>
第二种是数组赋值(常用,推荐)
// 映射this.count为store.state.count
computed: mapState([
'count'
])
案例演示:
// store>index.js
export default new Vuex.Store({
state: {
count: 3,
sum: 6,
add: 9
}
})
// state.vue
<script>
import {mapState} from 'vuex'
export default new Vue({
computed: mapState([
'count',
'sum',
'add'
])
})
</script>
<template>
<div id="state">
<p>{{count}}</p> // 3
<p>{{sum}}</p> //6
<p>{{add}}</p> // 9
</div>
</template>
第三种是展开运算符,在组件的方法中使用
// 使用对象展开运算符将此对象混入到外部对象中
computed: {
...mapState({
count: 'count',
sum: 'sum',
add: 'add'
})
}
2、mutations的使用
一个对象,保存的是更改state的函数,也只有它能更改state中的值,该函数可以传入两个参数,第一个参数为state,第二个参数为传入的数据,一般为一个对象
const mutations = {
add (state, n) {
state.count += n
}
}
在其他组件中调用触发函数,改变state中变量的值
// 触发函数里有两个参数,第一个为调用的mutations里面的函数的函数名,第二个为数据
this.$store.commit('add', 2)
// 例如:
<button @click="$store.commit('add', 2)">点击改变count</button>
如果想要触发事件像正常函数那样,如:@click="add",则需要通过mapMutations辅助函数,需要结合methods对象
// 将 this.increment() 映射为 this.$store.commit('adds')
// 载荷:this.increment(amount) 映射为 this.$store.commit('adds', amount)
引入mapMutations辅助函数
import {mapMutations} from 'vuex'
第一种对象方式
// 注意命名不要和state中的变量重名
methods: mapMutations({
adds: 'adds',
reduce: 'reduce'
})
案例演示:
第二种数组方式
methods: mapMutations([
'adds',
'reduce'
])
第三种展开运算符,在组件的方法中使用
methods: {
...mapMutations({
adds: 'adds',
reduce: 'reduce'
})
}
methods: {
...mapMutations([
'adds',
'reduce'
])
}
3、actions的使用
一个对象,保存的是触发mutations的函数,让mutations去修改state中的值,也可以是异步请求获取数据,获取数据后再通过context.commit()触发更改
// 相当于将$store.commit上的commit对象传进来,让方法体逻辑和代码更清晰明了
const actions = {
addsAction: ({commit}) => commit('adds')
}
// 传递参数
const actions = {
addsAction({commit}, n){commit('adds', n)}
}
// 传入任意参数,相当于store本身
const actions = {
reduceAction: (context) => context.commit('reduce')
}
// 传递参数
const actions = {
reduceAction(context,n){context.commit('reduce', n)}
}
在其他组件中触发actions函数
this.$store.dispatch('addsAction')
// 如果有参数的话,就传入参数,一般以对象的方式传入
this.$store.dispatch('addsAction', {
amount: 10
})
// 例如:
<button @click="$store.dispatch('addsAction', 1)">点击改变p的值</button>
<button @click="$store.dispatch('reduceAction', 1)">点击改变p的值</button>
如果想要触发事件像正常函数那样,如:@click="add",则需要通过mapActions辅助函数,需要结合methods对象方法
引入mapActions辅助函数
import {mapActions} from 'vuex'
第一种对象方式
methods: mapActions({
addsAction: 'addsAction',
reduceAction: 'reduceAction'
})
案例演示:
<button @click="addsAction(1)">点击改变p的值</button>
<button @click="reduceAction(1)">点击改变p的值</button>
第二种数组方式
methods: mapActions([
'addsAction',
'reduceAction'
])
第三种展开运算符,需要在组件方法中使用
methods: {
...mapActions({
addsAction: 'addsAction',
reduceAction: 'reduceAction'
})
}
// 或者数组形式
methods: {
...mapActions([
'addsAction',
'reduceAction'
])
}
4、getters的使用
getters相当于计算属性,用来重新修改state中变量的值,再返回对应的值,类似于vue的过滤器
const getters = {
getUsername: state => state.username + '1'
// 也可以这样写
getUsername (state) {
return state.username + '1'
}
}
getters的使用方式同前面的差不多
第一种,正常使用方式
this.$store.getters.getUsername
第二种,就是数组模式
computed: {
...mapGetters([
'getUsername'
])
}
第三种,就是对象模式
computed: {
...mapGetters({
getUsername: 'getUsername'(前面是重新定义的方法名,后面是你定义在getters里面的方法名)
})
}
五、属性变化监听
一般都是通过vue的watch来监听,watch监听分为普通监听和深度监听(对象)
// 例如,我们把state获取到并去监听数据变化来执行我们想要执行的事件
computed: {
...mapState([
'username'
])
}
watch: {
username (newVal, oldVal) {
console.log('新值:' + newVal + '旧值:' + oldVal)
// to do something here
}
}
如果返回一个对象,我们要监听对象或者对象的某一个属性变化,则这样做
// 普通监听
computed: {
...mapGetters([
'userInfo'
])
},
watch: {
userInfo (newVal, oldVal) {
console.log('新值:' + newVal + '旧值:' + oldVal)
// to do something here
}
// 必须
deep: true
}
// 监听对象某个属性的变化
userInfo.username (newVal, oldVal) {
console.log('新值:' + newVal + '旧值:' + oldVal)
// to do something here
}
// 如果想要对象中某个属性值改变时执行操作,可以通过computed来作为中间层来实现
computed: {
username () {
return userInfo.username
}
}
watch: {
username (newVal, oldVal) {
console.log('新值:' + newVal + '旧值:' + oldVal)
// to do something here
}
}
六、注意事项
1、actions与mutations的区别
actions区别于mutations的地方在于mutations只能进行同步更改,而actions中的更改可以是异步执行。
所以基本上所有用户执行的直接数据更改都是触发mutations属性函数执行,而需要与后端进行数据交互的数据更改通常是通过actions属性函数去执行。
2、定义actions与mutations属性函数的注意事项
定义mutations属性函数时必须传递的第一个参数是state,因为要对state进行更改,第二个参数代表传入的新参数。
mutations属性函数只接受两个参数,如果要同时更改多个属性值,可以通过对象传入。
在actions属性函数中可以通过context.commit()方法触发mutations属性函数。定义actions属性函数时,必须传递的第一个参数是context,用于触发mutations函数。
3、触发actions与mutations属性函数的方法
在子组件中通过this.$store.commit()方法触发mutations属性函数。在注册store的Vue实例中(第三步中将会讲到)可以通过store.commit()触发。
commit函数第一个参数是mutations的属性函数名,第二个参数是传入的新值。
actions属性函数中可以进行异步操作,比如通过ajax或者Vue.Resource()进行数据获取,获取数据后再通过context.commit()触发更改。
触发actions属性函数使用this.$store.dispatch()或者store.dispatch() (在注册store的Vue实例中)函数。dispatch函数传递的一个参数是actions属性函数名称。
如果希望在Vue实例创建完成还未挂载时就从后端获取数据,则可以在created钩子函数中调用actions属性函数。
4、在组件中访问数据中心state的注意事项
在Vue实例中可以通过this.$store.state对象获取state中的数据。如果希望在state中的数据发生更改之后,组件会自动更新,则应该使用组件的computed属性定义数据,而不是通过data属性定义。
如果使用data定义组件数据,则state中的数据发生更改之后组件不会发生变化。