009_Vuex

Vuex

1、理解 vuex

1.1、vuex 是什么

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pnNwE7vs-1691737144973)(C:\Users\ASUS\Desktop\java\20_vue\image\1687521800157.png)]

1.2、vuex和全局事件总线实现读写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iQXFUwHm-1691737144974)(C:\Users\ASUS\Desktop\java\20_vue\image\1687522286162.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4wRwOOix-1691737144974)(C:\Users\ASUS\Desktop\java\20_vue\image\1687522407015.png)]

1.3、什么时候使用Vuex(共享)

  • 多个组件依赖于同一个数据
  • 来自不同组件的行为需要变更同一状态

2、案例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JThPYio2-1691737144975)(C:\Users\ASUS\Desktop\java\20_vue\image\1687523629054.png)]

2.1、不使用vuex写

<template>

    <div>
        <h1>当前求和为:{{ sum }}</h1>
        <select v-model.number="number">
            <option :value="1">1</option>
            <option :value="2">2</option>
            <option :value="3">3</option>
        </select>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementOdd">当前求和为奇数再加</button>
        <button @click="incrementWait">等一等再加</button>
    </div>

</template>

<script>
    export default {
        name: "NumberCount",
        data() {
            return {
                sum: 0,
                number: 1 //用户选择的数字
            }
        },
        methods: {
            increment() {
                this.sum += this.number
            },
            decrement() {
                this.sum -= this.number
            },
            incrementOdd() {
                if (this.sum % 2) {
                    this.sum += this.number
                }
            },
            incrementWait() {
                setTimeout(() => {
                    this.sum += this.number
                },1000)
            }
        }
    }
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5b3pUip-1691737144976)(C:\Users\ASUS\Desktop\java\20_vue\image\1687523739878.png)]

2.2、使用vuex

2.2.1、Vuex工作原理图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-83wQfpRx-1691737144977)(C:\Users\ASUS\Desktop\java\20_vue\image\1687526674368.png)]

2.2.2、搭建Vuex环境
  • 安装:npm i vuex@3(vue2中要用vuex3,vue3要用vuex4)

  • 引入和使用插件:Vue.use(Vuex)

  • 创建store,并且再vm创建的时候对store属性赋值

  • vc====>store

  • 从main.js中出发

import Vue from "vue";
import App from './App'
//引入vuex
import Vuex from 'vuex'
//使用vuex插件,这段代码必须再 import store之前执行,但是这里没有办法控制,所有写再 store/index.js中请实现
// Vue.use(Vuex)

//引入store
import store from './store/index'

Vue.config.productionTip = false

//只有我们use了Vuex,那么我们就可以再new vm的时候,传入一个store对象了,然后所有的组件就会有store
new Vue({
    render: p => p(App),
    //再创建vm的时候,赋值store属性
    store: store
}).$mount('#app')
  • 再在src下创建store/index.js中取创建store
//该文件用于创建Vuex中最为核心的 store,用户管理:Actions、Mutations、State

import Vue from "vue";
//引入vuex
import Vuex from 'vuex'
//使用vuex
Vue.use(Vuex)

//准备actions---用于响应组件中的动作
const actions = {}

//准备Mutations---用于操作数据(state)
const mutations = {}

//准备state----用于存储数据
const state = {}

//创建并且暴露 store
export default new Vuex.Store({
    actions,
    mutations,
    state
})
  • 效果:每个组件以及vm都可以看到store,就可以调用对应的API进行实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vD2hJwyk-1691737144978)(C:\Users\ASUS\Desktop\java\20_vue\image\1687531301320.png)]

2.2.3、如何从vuex中读取数据
  • 在store/index.js中的state属性中定义 需要被共享的数据
//准备state----用于存储数据
const state = {
    sum: 0
}
  • 引入我们通过Vue.use(Vuex),所有每个vc和vm都存在 $store,则我们就可以通过它来获取值
<!-- 想办法读取到state中的Sum-->
<h1>当前求和为:{{ $store.state.sum }}</h1>
2.2.4、如何修改vuex中的数据(以加法为例子)
  • 按钮点击调用,dispatch方法,并且定义操作的类型和参数
//NumberCount组件中
methods: {
    increment() {
        //调用dispatch方法
        //第一个参数:派遣的行为类型
        //第二个参数:加几
        this.$store.dispatch('jia', this.number)
    }
}
  • 在store/index.js中配置actions,并且调用commit方法
    • 其实也可以直接在actions中通过:miniStore.state.sum + = value 来操作数据,但是这样的话开发者工具就会失效
const actions = {
    //这里需要定义dispatch的操作类型,key:类型;value:回调函数
    //简写形式,这个函数可以接收到参数,并且需要调用commit
    //接收的第一个参数:简写版本的store上下问
    //接收的第二个参数:调用dispatch方法的时候传递的参数
    jia(miniStore, value) {
        //这里面可以写一些相应的业务逻辑:比如ajax请求等,如果你这里没有定义的业务逻辑,可以不用写actions,但是对应的this.$store.dispatch ,则需要改为 this.$store.commit('JIA',value)
        miniStore.commit('JIA', value)
        
        //当jia这个函数体存在很多代码的时候,也可以调用actions中的其它的方法
        minStore.dispacth('xxx',value)
    }
}
  • 在store/index.js中配置mutations,它可以真的的操作到store
//准备Mutations---用于操作数据(state)
const mutations = {
    //这里commit调用之后就会执行到mutations中的对应的函数
    //参数1:state中的值
    //参数2:actions调用commit传递的参数
    JIA(state, value) {
        state.sum += value
    }
}

3、store中的getters配置项

3.1、定义和注册getters

  • 定义getters
//配置getters--用于将state中的数据进行加工
const getters = {
    //函数会接收到state参数,并且函数是跟计算属性一样,需要return
    bigSum(state) {
        return state.sum * 10
    }
}
  • 注册getters
//创建并且暴露 store
export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
})

3.2、使用getters中的属性

<h1>当前求和的10倍为:{{ $store.getters.bigSum }}</h1>

4、mapState的引入

4.1、问题

<h1>当前求和为:{{ $store.state.sum }}</h1>
<h1>当前求和的10倍为:{{ $store.getters.bigSum }}</h1>
<h1>我在{{ $store.state.school }}学习{{ $store.state.subject }}</h1>

<!--
	在这三段代码中,这个$store.state经常被重复使用,导致表达式的内容过长
-->

4.2、使用计算属性

//使用computed计算属性来实现这个功能
//问题:我们发现,这个he、xuexiao、xueke这些函数也出现重复的请求,所以我们可以通过mapState告诉它he、sum让它自动生成代码就可以解决这个问题
computed: {
    he() {
      return this.$store.state.sum
    },
    xuexiao() {
      return this.$store.state.school
    },
    xueke() {
      return this.$store.state.subject
    },
    bigSum() {
      return this.$store.getters.bigSum
    }
  },
<h1>当前求和为:{{ he }}</h1>
<h1>当前求和的10倍为:{{ bigSum }}</h1>
<h1>我在{{ xuexiao }}学习{{ xueke }}</h1>

4.3、使用mapState解决问题

  • 第一步:引入mapState
import {mapState} from 'vuex'
  • 第二步:调用mapState函数并且将返回值存入计算属性中
computed: {
    //需要参数对象,返回的也是对象,然后将返回的数据放入到computed中。 ...的意思是将这个对象中的每一个数据,放入到computed中
    ...mapState({he: 'sum', xuexiao: 'school', xueke: 'subject'}),
        
    //方式二(数组写法):取数据的时候也要根据sum、school、subject获取
    ...mapState(['sum','school','subject'])
},
  • 第三步:可以使用你定义的key值取到对于的值
<h1>当前求和为:{{ he }}</h1>
<h1>当前求和的10倍为:{{ bigSum }}</h1>
<h1>我在{{ xuexiao }}学习{{ xueke }}</h1>

5、mapGetters的引入

  • mapGetters跟mapState用法一致

6、mapMutations的引入

  • 解决直接与mutations对话的方法

6.1、引出问题

//调用commit是直接与mutations直接对话,但是存在代码重复的部分
//我们需要传入函数名称、操作类型;当然在点击事件的时候需要传入参数
methods: {
    increment() {
    	this.$store.commit('JIA', this.number)
    },
    decrement() {
    	this.$store.commit('JIAN', this.number)
    }
}

6.2、mapMutations解决问题

//引入mapMutations
import {mapState, mapGetters, mapMutations} from 'vuex'

methods: {
  ...mapMutations({increment: 'JIA', decrement: 'JIAN'}),
},
<!--
	我们必须在这里传递参数,不然没有办法给生成的函数传递我们想给的参数
-->
<button @click="increment(number)">+</button>
<button @click="decrement(number)">-</button>

7、mapActions的引入

  • mapActions直接跟action对话,跟mapMutations的用法一致

8、总结mapxxxx

  • mapState和mapGetters是存放到组件的computed属性当中的
  • mapActions和mapMutitions是存放到组件的methods属性当中的

9、vuex模块化

9.1、问题-以state为例

//对于我们的sum、school、subject是操作求和模块的,对于personList是操作人员模块的,当我们都将它写在state中,难免会混乱,所以出现vuex的模块化
const state = {
    sum: 0,
    school: '尚硅谷',
    subject: '前端',
    personList: [
        {id: '001', name: '张三'},
        {id: '002', name: '李四'},
    ]
}

//所以其它的配置actions、mutitions、getters也会出现同样的问题

9.2、对store/index.js进行改造–分模块

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex)

//求和方面的配置项
const countOptions = {
    //为了方便mapState通过类型获取
    namespaced:true,
    actions: {
        jiaOdd(miniStore, value) {
            //这里面可以写一些业务逻辑,比如ajax请求等等
            if (miniStore.state.sum % 2) {
                miniStore.commit('JIA', value)
            }
        },

        jiaWait(miniStore, value) {
            setTimeout(() => {
                miniStore.commit('JIA', value)
            }, 500)
        }
    },
    mutations: {
        JIA(state, value) {
            state.sum += value
        },
        JIAN(state, value) {
            state.sum -= value
        }
    },
    state: {
        sum: 0,
        school: '尚硅谷',
        subject: '前端',
    },
    getters: {
        bigSum(state) {
            return state.sum * 10
        }
    }
}

//人员方面的配置项
const personOptions = {
    namespaced:true,
    actions: {},
    mutations: {
        ADD_PERSON(state, personObj) {
            state.personList.unshift(personObj)
        }
    },
    state: {
        personList: [
            {id: '001', name: '张三'},
            {id: '002', name: '李四'},
        ]
    },
    getters: {}
}


export default new Vuex.Store({
    modules: {
        countOptions,
        personOptions
    }
})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ujoz6et7-1691737144979)(C:\Users\ASUS\Desktop\java\20_vue\image\1688397137959.png)]

9.3、如何获取和使用

  • 简写方式的使用
 methods: {
     //countOptions下的JIA和JIAN,注意如果使用这种格式,需要添加namespaced配置为true
    ...mapMutations('countOptions',{increment: 'JIA', decrement: 'JIAN'}),

    ...mapActions('countOptions',{incrementOdd: 'jiaOdd', incrementWait: 'jiaWait'})
  },
  computed: {
    ...mapState('countOptions', ['sum', 'school', 'subject']),
    ...mapState('personOptions', ['personList']),

    ...mapGetters('countOptions',['bigSum'])
  },
  • 原生写法
methods: {
    addPerson() {
        if (this.name === '') {
            alert("输入框不能为null")
            return
        }
        const personObj = {id: nanoid(), name: this.name}
        //这里需要使用 / 来往下寻找
        this.$store.commit('personOptions/ADD_PERSON', personObj)
        this.name = ''
    }
},

9.4、严格模块化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1tjC6KJq-1691737144979)(C:\Users\ASUS\Desktop\java\20_vue\image\1688398137646.png)]

sum’, ‘school’, ‘subject’]),
…mapState(‘personOptions’, [‘personList’]),

...mapGetters('countOptions',['bigSum'])

},


- 原生写法

```javascript
methods: {
    addPerson() {
        if (this.name === '') {
            alert("输入框不能为null")
            return
        }
        const personObj = {id: nanoid(), name: this.name}
        //这里需要使用 / 来往下寻找
        this.$store.commit('personOptions/ADD_PERSON', personObj)
        this.name = ''
    }
},

9.4、严格模块化

[外链图片转存中…(img-1tjC6KJq-1691737144979)]

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值