这篇文章将更加详细讲解Vuex的使用,简单讲解见 Vuex(一)
Vuex_2
当多个组件想使用同一个数据的时候,就可以使用Vuex
1、安装Vuex
npm i vuex -S
2、导入Vuex并让vue管理
首先新建一个文件夹:store (一般都这么建)
然后在文件夹里创建 index.js
1、安装插件
2、创建对象
3、导出store对象
4、去main.js挂载一下
//这个 from 'vue' from后面那个是使用npm导入的时候所使用的名字,可以在配置文件中更改
import Vue from 'vue'
import Vuex from 'vuex'
//1、安装插件
Vue.use(Vuex)
//2、创建对象,对象中的属性是固定的这几项
const store = new Vuex.Store({
state: {
//放数据
counter: 1000
},
mutations:{
//放方法,同步方法
},
actions:{
//放异步方法
},
getters:{
//类似于vue里的计算属性
},
modules:{
}
})
//3、导出store对象
export default store
//4、去main.js挂载一下
main.js
在这里挂载之后就意味着所有的vue组件都有一个$store对象
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false
new Vue({
el: '#app',
components: { App },
template: '<App/>',
// 在这里挂载之后就意味着所有的vue组件都有一个$store对象
store
})
3、使用Vuex数据(state)方式
因为挂载之后就意味着所有的vue组件都有一个$store对象,所以可以按照如下方式使用
HelloVuex.vue
App.vue
<template>
<div id="app">
<h2> {{message}} </h2>
<h2> {{$store.state.counter}} </h2>
<button @click="counter++">+</button>
<button @click="counter--">-</button>
<hello-vuex></hello-vuex>
</div>
</template>
<script>
import HelloVuex from './components/HelloVuex'
export default {
name: 'App',
components: {
HelloVuex
},
data() {
return {
message: '我是APP组件',
counter: 0
}
},
}
</script>
<style>
</style>
结果:此时两个组件都使用的Vuex里面的数据
4、更新、修改Vuex数据(state)方式–mutations–放同步方法
例子一:基本使用
不允许组件直接修改state的值,建议组件通过使用 mutations 中的方法来改
修改mutations:添加两个方法
mutations: {
//方法
increment(state) {
state.counter++
},
decrement(state) {
state.counter--
}
},
修改App.vue
在这里添加两个方法,然后在方法中使用mutations中的方法操作state中数据
methods: {
add() {
this.$store.commit('increment')
},
sub() {
this.$store.commit('decrement')
}
},
细节讲解:参数传递
提交单个参数
在commit的时候方法后跟参数,并且在Vuex中mutations对应的方法中使用第二个参数接收。
在App.vue添加
<button @click="addCount(5)">-</button>
方法中添加:
addCount(count){
this.$store.commit('incrementCount',count)
}
在index.js中添加:
incrementCount(state ,count) {
state.counter += count
},
提交多个参数
在commit的时候方法后跟参数,并且在Vuex中mutations对应的方法中使用第二个参数接收。此时这个参数是一个对象。
App.vue中添加
<button @click="addStu()">添加学生</button>
addStu(){
const stu = {id:5 ,name:'zyh', age:24 }
this.$store.commit('addStu',stu)
}
index.js中添加
addStu(state,stu){
state.students.push(stu)
}
提交风格
除了上述提交以外,提交还可以写为如下风格:
App.vue中添加
<button @click="addStu2(10)">添加学生2</button>
addStu2(){
this.$store.commit({
type: 'addStu2',
id:6,
name:'panda',
age:25
})
}
index.js中添加
addStu2(state,payload){
console.log(payload.name)
console.log(payload.id)
console.log(payload.age)
state.students.push(payload)
}
此时结果:会增加type类型还可以通过点的形式访问其中属性
综上:这种提交风格相当于提交的是一个对象,包含了type和要传递的参数(可单个也可以多个)
响应式规则
可以使用set添加属性,此时是响应式的
App.vue添加代码
<h2> {{$store.state.info}} </h2>
<button @click="updateinfo()">添加信息</button>
updateinfo(){
this.$store.commit('updateinfo')
}
在index中添加
info:{
name:'dululu'
}
updateinfo(state) {
// 这样添加属性的话不是响应式的 --- 无法同步到页面上
// state.info['address'] = '洛杉矶'
//这样是响应式的 set => 参数一:要修改的值 参数二:key或者数组下标 参数三:value(可以是字符串或者number)
Vue.set(state.info,'address','洛杉矶')
//响应式删除属性
//Vue.delete(state.info,'address')
},
结果:
5、getters基本使用
当一个数据需要经过一系列变化在使用的时候可以使用getters来实现,类似于vue中的计算属性
例子一:将counter平方
在getters添加代码:
getters: {
//类似于vue中的计算属性
powerCounter(state){
return state.counter * state.counter
}
},
使用方式:
在APP.vue中添加如下代码,注意方法不用加括号,当做属性来用就可以
结果:
例子二:获取大于20岁学生数据
state中添加:
students:[
{id:1 ,name:'zs',age:18},
{id:1 ,name:'ls',age:24},
{id:1 ,name:'ww',age:30},
{id:1 ,name:'zl',age:10}
]
getters添加:
more20stu:获取大于20岁学生
more20stuLength:获取大于20岁学生人数
moreAgeStu:获取大于指定年龄学生
因为getters中只有两个参数,第一个是state,第二个是getters,所以想要获取指定年龄不能传入第三个参数,但是可以返回一个带参数的函数,然后在函数中通过调用地方传递过来的参数进行判断
more20stu(state){
return state.students.filter(s => s.age >20)
},
more20stuLength(state,getters){
return getters.more20stu.length
},
moreAgeStu(state){
return function (age) {
return state.students.filter(s => s.age >age)
}
}
在App.vue添加:
<h2> {{$store.getters.more20stu}} </h2>
<h2> {{$store.getters.more20stuLength}} </h2>
<h2> {{$store.getters.moreAgeStu(12)}} </h2>
结果:
6、action的使用–放异步方法
如果是一个异步的方法我们要放入action,因为放入mutations中vuex是监听不到变化的。
对于一个异步方法我们需要如下调用:
在App.vue的方法中先通过dispatch引用action中的方法,然后在action的方法中引用mutation中的方法。
在App.vue中添加
<button @click="updateinfo2()">异步添加信息</button>
updateinfo2(){
this.$store.dispatch('aUpdataInfo','我是payload')
}
在index.js中的action中加
actions: {
//context:上下文
aUpdataInfo(context,payload) {
console.log(payload)
setTimeout(() => {
context.commit('updateinfo')
}, 1000);
}
},
如果要对数据进行操作后返回些东西:可以使用Promise
index.js中代码改为
aUpdataInfo(context, payload) {
return new Promise((resolve, rekect) => {
setTimeout(() => {
context.commit('updateinfo')
console.log(payload)
resolve('111111')
}, 1000);
})
}
App.vue中改为
updateinfo2(){
this.$store.dispatch('aUpdataInfo','我是payload').then(res =>{
console.log('里面完成了提交');
console.log(res);
})
}
注意上述代码中因为this.$store.dispatch调用了action中的方法,而在action方法中return了一个Promise,所以可以在App.vue调用action方法的那个后面 .then
7、modules的使用
模块有着自己的 state:{},mutations:{}, actions:{}, getters:{}
模块定义
在index.js添加
const moduleA = {
state:{},
mutations:{},
actions:{},
getters:{}
}
modules: {
a:moduleA
}
模块中state
修改 moduleA
state:{
name: 'Tim'
},
在App.vue中添加
<h2> {{$store.state.a.name}} </h2>
结果:
由此可以看出,vuex会自动把一个模块放到本身的state中去,调用的时候当做一个对象去调用
模块中的mutations
修改 moduleA
mutations:{
updateName(state,payload) {
state.name = payload
},
},
App.vue中添加
<h2> {{$store.state.a.name}} </h2>
<button @click="updateName">修改名字</button>
updateName(){
this.$store.commit('updateName','lisi')
}
结果:
可以看出,使用方式和以前一样,但是要注意,模块中的方法名字不要和store中的方法名字重复
模块中的getters
修改 moduleA
getters:{
fullname(state){
return state.name + '1111'
},
fullname1(state,getters,rootState){
return getters.fullname + rootState.counter
}
}
App.vue添加
<h2> {{$store.getters.fullname}} </h2>
<h2> {{$store.getters.fullname1}} </h2>
结果:
由此可看出,调用时和之前一样,但是在模块中的getters中的方法有三个参数,第三个参数是获取 根 也就是 store中的state
模块中的action
修改 moduleA
actions: {
aUpdataName(context) {
setTimeout(() => {
context.commit('updateName','wangwu')
}, 1000);
}
},
App.vue
<h2> {{$store.getters.fullname}} </h2>
<h2> {{$store.getters.fullname1}} </h2>
<button @click="aUpdataName">异步修改名字</button>
aUpdataName(){
this.$store.dispatch('aUpdataName')
}
模块中的context有如下属性,这里的context.commit和store中context.commit不同,这里的只能提交模块中的,而store中的context.commit等同于store.commit
结果:
8、对象解构
想要获取对象中一些数据可以如下写:
此时console.log(name)就是why了
9、Vuex结构
我们先将index.js复制一份,然后进行抽取
新建如下文件,将index copy.js代码对应部分抽取进对应js文件,其中state是放在index copy.js中
形式为:
export default{
抽取内容
}
抽取后的index copy.js为
//这个 from 'vue' from后面那个是使用npm导入的时候所使用的名字,可以在配置文件中更改
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutation'
import actions from './action'
import getters from './getters'
import moduleA from './modules/moduleA'
//1、安装插件
Vue.use(Vuex)
const state = {
counter: 1000,
students: [
{ id: 1, name: 'zs', age: 18 },
{ id: 1, name: 'ls', age: 24 },
{ id: 1, name: 'ww', age: 30 },
{ id: 1, name: 'zl', age: 10 }
],
info: {
name: 'dululu'
}
}
//2、创建对象
const store = new Vuex.Store({
state,
mutations,
actions,
getters,
modules: {
a: moduleA
}
})
//3、导出store对象
export default store
//4、去main.js挂载一下
列举抽取样式:
moduleA
export default{
state: {
name: 'Tim'
},
mutations: {
updateName(state, payload) {
state.name = payload
},
},
actions: {
aUpdataName(context) {
setTimeout(() => {
context.commit('updateName','wangwu')
}, 1000);
}
},
getters: {
fullname(state) {
return state.name + '1111'
},
fullname1(state, getters, rootState) {
return getters.fullname + rootState.counter
}
}
}