51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Vue笔记[四]-动画、Vuex

QX-AI
GPT-4
QX-AI初始化中...
暂无预设简介,请点击下方生成AI简介按钮。
介绍自己
生成预设简介
推荐相关文章
生成AI简介

过渡与动画 {#过渡与动画}

Vue 封装了过渡与动画效果

作用:插入更新移除 Dom 元素时,自动在合适的时刻在过渡标签添加移除不同的类名 ,只需写动画和过渡效果并应用到对应时刻的类名上,而无需手动操作 Dom

过渡标签:
(1) <transition> 包裹需要动画效果的单个 元素
(2) <transition-group> 包裹需要动画效果的多个 元素,每个元素都需要配置 Key 属性

不同时刻样式类名:
(1) 控制元素进入的样式

  1. v-enter 进入的起点
  2. v-enter-active 进入过程中
  3. v-enter-to 进入的终点

(2) 控制元素离开的样式

  1. v-leave 离开的起点
  2. v-leave-active 离开过程中
  3. v-leave-to 离开的终点

过渡标签添加 name 属性来配置类名的前缀 ,默认是 v ,如进入起点的类名是 .v-enter<前缀>-enter

离开和进入: 即元素的插入更新移除 ,通常配合 v-showv-if 来控制

添加 appear 属性让动画在网页首次加载时、元素首次插入时也触发

元素飞入飞出案例 {#元素飞入飞出案例}

分别用动画属性 animate过渡属性 transition 配合不同的类名实现相同的动画效果

模板结构:

|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | <template> <div> <button @click="isShow=!isShow">显示隐藏</button> <transition name="hello" appear> <h1 v-show="isShow" class="title">你好</h1> </transition> </div> </template> |

交互:

|-------------------------|-----------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | export default { name: 'Test-', data(){ return{ isShow: true, } } } |

使用动画属性 animate 配合 .v-enter-active.v-leave-active

|---------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | .title { background: rgb(114, 196, 219); } /* 进入过程的动画 */ .hello-enter-active{ animation: titleShow 1s; } /* 离开过程的动画 */ .hello-leave-active{ animation: titleShow 1s reverse; } /* 动画 */ @keyframes titleShow{ from { transform: translateX(-100%); } to{ transform: translateX(0px); } } |

过渡属性 transition 配合进入和离开的起点、终点的样式实现动画

|------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | .title { background: rgb(114, 196, 219); } /* 设置进入起点的样式 */ .hello-enter { transform: translateX(-100%); } /* 设置进入终点的样式 */ .hello-enter-to { transform: translateX(0); } /* 设置离开起点的样式 */ .hello-leave { transform: translateX(0); } /* 设置离开终点的样式 */ .hello-leave-to { transform: translateX(-100%); } /* 设置 transition 属性 */ .hello-enter-active, .hello-leave-active { transition: 0.5s linear; } |

第三方动画库 {#第三方动画库}

有许多优秀的动画库,引入即可使用,以 animate.css 为例

安装: npm install animate.css --save

使用第三方库时,通常要在过渡标签 上通过几个属性来自定义样式类名的后缀 ,name属性设置前缀
(1) enter-active-class 属性:设置进入过程中 的样式类名
(2) leave-active-class 属性:设置离开过程中的样式类名

使用: 引入动画库后,在过渡标签 上设置name前缀以使用该动画库,然后在animate.css文档中挑选动画效果,将进入动画的类名设置到 enter-active-class 属性中,离开动画的类名设置到 leave-active-class 属性中,通过设置样式类名后缀来使用具体的动画效果

案例:

|------------------------------|-------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | // 引入动画库 import 'animate.css' export default { name: 'Test-', data() { return { isShow: true, } } } |

模板结构:

|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <template> <div> <button @click="isShow = !isShow">显示隐藏</button> <!-- 设置动画 --> <!-- name设置前缀表示使用animate.css动画库 --> <!-- 通过设置样式类名后缀来使用具体的动画效果 --> <transition name="animate__animated animate__bounce" enter-active-class="animate__swing" leave-active-class="animate__backOutUp" appear > <h1 v-show="isShow" class="title" key="1">你好</h1> </transition> </div> </template> |

CSS 样式,因为使用了动画库,就无需自己写动画了

|---------------|----------------------------------------------------| | 1 2 3 | .title { background: rgb(114, 196, 219); } |

ToDoList添加动画 {#ToDoList添加动画}

给 ToDoList 案例中每个todo 的新增和删除添加动画

效果:

修改 ToDoList.vue 组件

|---------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <template> <div class="todo-list"> <ul> <transition-group name="todo"> <ListItem v-for="item in todos" :key="item.id" :todo="item"></ListItem> </transition-group> </ul> </div> </template> <!-- ...... --> <style> /* ........ */ /* 动画 */ .todo-enter, .todo-leave-to { opacity: 0; transform: translateX(-50%); } .todo-enter-to, .todo-leave { opacity: 1; transform: translateX(0); } .todo-enter-active, .todo-leave-active { transition: all 0.3s; } </style> |

Vue中发请求 {#Vue中发请求}

在 Vue 中发请求通常用 Axios

安装: npm i axios

Axios 笔记: AJAX请求相关-Axios

Vue-cli配置代理 {#Vue-cli配置代理}

当后端没有配置 cors 时,本地开发环境请求后端API就会产生跨域问题

服务器之间通信没有跨域问题,可以在本地配置一个代理服务器去请求API

vue.config.js 中添加 devServer 配置项,以在开发环境下将 API 请求代理到 API 服务器

|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 | const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, devServer: { proxy: '<转发的url>' } }) |

配置代理后,将请求的 baseURL 改为本地ip+端口,如 120.0.0.1:8080,代理服务会将请求转发,自己去请求实际的API地址,然后返回数据

有些时候并不想所有发往自身获取资源的请求都被代理转发,实际想获取的是本地public文件夹下的资源,而不是远程API的

可以写完整版 devServer 配置,匹配路径去选择性代理

**作用:**可以配置多个代理,且可以灵活的控制发往本地的请求是否走代理转发

|---------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, devServer: { proxy: { // 匹配路径代理 '/api': { target: '<url>', // 代理目标的baseURL ws: true, // 用于支持websocket changeOrigin: true, // 伪造Host为代理目标baseURL pathRewrite: {'<正则匹配路径>', '<替换内容>'} // 重写路径 }, '/foo': { target: '<other_url>' } } } }) |

~~还是让后端配cors好~~

获取所有账单 {#获取所有账单}

在 NodeJS 中写过一个记账本案例,里面写了一套完整的 API,刚好拿来用

KeepingBook-API文档

**功能:**点击登陆提示登陆中,登陆成功提示成功登陆,点击获取账单,提示加载中,请求成功后展示所有账单的列表

App.vue

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | <template> <div> <button @click="login">登录获取token</button> <button @click="getData">获取所有账单</button> <!-- 提示 --> <div v-show="tip !== ''" class="tip">{{ tip }}</div> <ul> <li v-for="(item, index) in kpb" :key="item.id"> {{ index + 1 }}: {{ item.matter }} | {{ item.date }} | {{ item.type }} | {{ item.account }} </li> </ul> </div> </template> <script> import axios from "axios"; axios.defaults.baseURL = 'https://kpb.qcqx.cn'; export default { name: "App", data() { return { // 登陆返回的token token: "", // 账单数据 kpb: "", // 提示 tip: "欢迎,请登陆", } }, methods: { // 登陆 login() { this.kpb = ""; this.tip = "登陆中...."; axios({ url: '/api/login', method: 'post', data: { username: 'qx', password: '123' }, // 请求超时 timeout: 5000 }).then(res => { // 响应体对象 console.log(res.data); this.token = res.data.data.token; this.tip = "登陆成功"; }).catch(err => { console.log(err); this.tip = "登陆失败"; }); }, // 获取账单 getData() { this.kpb = ""; this.tip = "账单加载中...."; axios({ url: '/api', method: 'get', headers: { token: this.token }, // 请求超时 timeout: 5000 }).then(res => { // 响应体对象 console.log(res.data); if (res.data.data === null) { this.tip = res.data.msg; return; } this.kpb = res.data.data; this.tip = ""; }).catch(err => { console.log(err); this.tip = "获取账单失败"; }); } } }; </script> |

插槽 {#插槽}

插槽 是由子组件 在模板的合适位置通过 <slot> 定义的

作用: 让父组件可以向子组件定义的插槽处插入 html 结构

插槽的种类:
(1) 默认插槽: 简单地将组件标签中所有html结构放到插槽处
(2) 具名插槽: 通过 <slot> 上的 name 属性区分插槽,通过 v-slot:<插槽名> 将html插入到指定插槽
(3) 作用域插槽: 用于数据在子组件中,且不将数据外传,根据数据生成的结构由父组件决定的情况

注意:
(1) 父组件中要插入插槽的html结构也是在父组件中完成模板解析的,可以访问父组件中的数据,而不能直接访问到自组件的数据
(2) 三种插槽可以混合使用

默认插槽 {#默认插槽}

简单地将组件标签中所有html结构放到插槽处 父组件

|-------------------|-------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 | <ListBox> <ul> <li v-for="(item, index) in arr" :key="index">{{ item }}</li> </ul> </ListBox> |

子组件

|-------------|-------------------------------------| | 1 2 | <!-- 定义插槽 --> <slot></slot> |

具名插槽 {#具名插槽}

通过 <slot> 上的 name 属性区分插槽,通过 v-slot:<插槽名> 将html插入到指定插槽

v-slot: 可以简写为 # 父组件

|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | <ListBox> <template v-slot:list> <ul><li v-for="(item, index) in arr" :key="index">{{ item }}</li></ul> </template> <!-- v-slot: 简写为 # --> <template #other> <h2>chuckle</h2> </template> </ListBox> |

子组件

|-------------|--------------------------------------------------------------| | 1 2 | <slot name="list"></slot> <slot name="other"></slot> |

作用域插槽 {#作用域插槽}

用于数据在子组件中,且不将数据外传,根据数据生成的结构由父组件决定的情况

子组件通过 <slot> 的标签属性传数据给父组件(只能在组件标签中使用)
父组件通过 #<插槽名>="obj" 的 obj 接收一个对象,对象中有传过来的属性名和属性值(数据) 父组件

|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 | <ListBox> <!-- default代表无名插槽 --> <template #default="{arr}"> <ul><li v-for="(item, index) in arr" :key="index">{{ item }}</li></ul> </template> <!-- v-slot接收到的是一个对象 --> <template #other="obj"> <div>{{ obj.x }} | {{ obj.y }}</div> </template> </ListBox> |

子组件

|-----------------|-----------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | <!-- 将子组件的数据传给父组件内的组件标签中使用 --> <slot :arr="arr"></slot> <!-- 传给父组件多个数据 --> <slot name="other" :x="x" :y="y"></slot> |

Vuex {#Vuex}

在实现组件间通信 时,无论是全局事件总线 还是消息订阅与发布,大量的声明事件或消息名,会让代码变得臃肿、难以维护

Vuex 是实现集中式状态(数据)管理 的一个 Vue 插件,对 Vue 应用中多个组件的共享状态进行集中式的管理(读/写)

安装: npm install vuex --save Vue2 只能使用 Vuex3

功能: 将原本某一组件管理的数据拿出来给 Vuex 管理,所有组件都能看到 Vuex 中管理数据的仓库 Store,以及使用仓库所提供的,对数据读和写的方法

何时用 Vuex 管理状态(数据):
(1) 多个组件依赖于同一状态
(2) 来自不同组件的行为需要变更同一状态

Vuex工作原理 {#Vuex工作原理}

Vuex 工作原理图:

Vuex 有三个重要组成部分 ,这三个部分都在 Store 实例上,本质都是对象

  1. **Actions:**进行一些业务逻辑(异步)的操作,如发送 AJAX 请求,不直接对数据进行操作
  2. **Mutations:**对数据进行直接的维护,有许多对数据进行操作的自定义方法
  3. **State:**状态(数据),存放着多个组件共享的数据

Vuex的工作循环:

  1. 组件通过 dispatch() 调用 Actions 中的方法,触发一些业务逻辑
  2. Actions 中业务逻辑处理完后,在合适时机调用 commit() 触发 Mutations 中对数据进行直接操作的方法
  3. 然后 State 中数据响应式 地变化,触发对应视图更新

注意: 如果对数据的操作不带有更多的业务逻辑,组件也可以直接调用 commit() 方法

Store:Vuex.Store() 构造函数创建,提供了三个重要组成部分以及 dispatch()commit() 等各种API

搭建Vuex环境 {#搭建Vuex环境}

新建一个JS文件,用于配置和创建 Store 实例,通常是 src/store/index.js

|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import Vue from 'vue'; import Vuex from 'vuex'; // 使用vuex插件 Vue.use(Vuex); // 创建三个重要组成部分 const actions = {} const mutations = {} const state = {} // 创建store实例,并暴露出去 export default new Vuex.Store({ // 将三个重要部分都交给store管理 actions, mutations, state }); |

然后在 new Vue() 时将 Store 实例作为配置项传入

目的: 让 vm 和 vc 身上新增一个 $store 属性,让所有组件都能访问到数据仓库 store main.js

|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import Vue from "vue"; import App from "./App.vue"; // 引入store实例 import store from "./store"; Vue.config.productionTip = false; new Vue({ el: "#app", // 使用store store, render: h => h(App), }) |

纯Vue求和案例 {#纯Vue求和案例}

App.vue

|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <template> <div> <CountNum></CountNum> </div> </template> <script> import CountNum from "./components/CountNum.vue"; export default { name: "App", components: { CountNum, } }; </script> |

|---------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <template> <div> <h3>{{ sum }}</h3> <select v-model.number="num"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button @click="add">+</button> <button @click="reduce">-</button> <button @click="addOdd">当前总和是奇数再加</button> <button @click="addWait">延迟1s再加</button> </div> </template> <script> export default { name: "CountNum", data() { return { // 总和 sum: 0, // 选择的数字 num: 0, } }, methods: { // 加 add() { this.sum += this.num; }, // 减 reduce(){ this.sum -= this.num; }, // 当前总和是奇数再加 addOdd(){ if(this.sum%2){ this.sum += this.num; } }, // 延迟1s再加 addWait(){ setTimeout(()=>{ this.sum += this.num; }, 1000) } }, } </script> |

Vuex版求和案例 {#Vuex版求和案例}

对纯 Vue 版进行修改,将 sum 交给 vuex 的 store 管理,将直接对数据的操作放到 Mutations 中,将带有业务逻辑的操作放到 Actions 中

一些总结与注意:

  1. 虽然 $store.state.xxx = xxx 直接修改数据,也能响应式更新视图,但这样做无法被 vuex-tools 所监视,所以不要直接修改数据
  2. commit()dispatch() 都只能传入两个参数,第一个是要触发的函数名,第二个是传入的数据
  3. actions 中的函数收到两个参数,第一个 context 指上下文,是一个 mini 的 store,有部分 store 上的属性和方法,第二个 valuedispatch() 传来的数据
  4. mutations 中的函数也收到两个参数,第一个 state 是 store 中的数据,第二个 valuecommit() 传来的数据

CountNum.vue

|---------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <template> <div> <!-- 通过vc身上的$store.state获取数据 --> <h3>{{ $store.state.sum }}</h3> <select v-model.number="num"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button @click="add">+</button> <button @click="reduce">-</button> <button @click="addOdd">当前总和是奇数再加</button> <button @click="addWait">延迟1s再加</button> <button @click="$store.state.sum = 1">测试直接修改数据</button> </div> </template> <script> export default { name: "CountNum", data() { return { // 选择的数字 num: 0, } }, methods: { // 加 add() { // 传入函数名去匹配对数据的操作和选择的数字 this.$store.commit('add', this.num) }, // 减 reduce(){ this.$store.commit('reduce', this.num) }, // 当前总和是奇数再加 addOdd(){ this.$store.dispatch('addOdd', this.num) }, // 延迟1s再加 addWait(){ this.$store.dispatch('addWait', this.num) } }, } </script> |

/store/index.js

|------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import Vue from 'vue'; import Vuex from 'vuex'; // 使用vuex插件 Vue.use(Vuex); // 有业务逻辑的操作放在actions中 const actions = { // context:上下文,一个mini都store,有store中的部分属性和方法 // value,组件中dispatch()传过来的值 addOdd(context, value) { if (context.state.sum % 2) { // 业务逻辑处理完后调用上下文中的commit() context.commit('add', value); } }, addWait(context, value) { setTimeout(() => { context.commit('add', value); }, 1000) } } // 没有业务逻辑的操作放在mutations中 const mutations = { // mutations中的函数收到两个参数 // state:store中的数据,value:commit()传过来的值 add(state, value) { state.sum += value; }, reduce(state, value) { state.sum -= value; }, } const state = { // 数据 sum: 0, } // 创建store实例 export default new Vuex.Store({ actions, mutations, state }); |

getters配置项 {#getters配置项}

除了三个重要组成部分必须作为 Store 的配置项之外,还有其它配置项

getters 和计算属性差不多,对数据进行加工后再返回,其中的函数收到一个参数 state

|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 准备getters const getters = { // 对sum进行放大10倍 bigSum(state){ return state.sum * 10; } } export default new Vuex.Store({ actions, mutations, state, // 配置getters getters }); |

通过 $store.getters 获取加工后的数据

|-------------|------------------------------------------------------------------------------| | 1 2 | <h3>{{ $store.state.sum }}</h3> <h3>{{ $store.getters.bigSum }}</h3> |

mapState和mapGetters {#mapState和mapGetters}

当一个组件需要获取多个状态 时,总在模板中用 $store.state.xxx 获取状态,代码重复且冗余

即使是手动写成计算属性 ,也要重复去 return $store.state.xxx

mapState()mapGetters() 可以帮我们生成状态的计算属性,以此简洁地使用状态

需要引入后才能使用:

|-----------|----------------------------------------------------| | 1 | import { mapState, mapGetters} from 'vuex' |

使用注意:

  1. 传入一个对象,key-value 是 <生成的计算属性名>:<状态名或getter名>
  2. 返回值是包含多个计算属性的对象,需要用 ... 对象展开运算符,将其与组件的计算属性对象合并

|---------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // import { mapState, mapGetters} from 'vuex' export default { /* .... */ computed: { test(){ return 'test' }, // 对象展开运算符 ...mapState({ sum: 'sum' }), ...mapGetters({ bigSum: 'bigSum' }) }, /* .... */ } |

当要生成的计算属性名状态名或getter名 一样时,可以使用数组简写形式,传入数组,元素是状态名或getter名

|-----------|---------------------------| | 1 | mapState(['sum']) |

mapActions和mapMutations {#mapActions和mapMutations}

在 methods 中也写了很多看起来重复的代码

|---------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 加 add() { // 传入函数名去匹配对数据的操作和选择的数字 this.$store.commit('add', this.num) }, // 减 reduce(){ this.$store.commit('reduce', this.num) }, // 当前总和是奇数再加 addOdd(){ this.$store.dispatch('addOdd', this.num) }, // 延迟1s再加 addWait(){ this.$store.dispatch('addWait', this.num) } |

mapActions()mapMutations() 能够生成调用 commit 和 dispatch 方法的方法

用法和 mapState 和 mapGetters 差不多

|-----------------------|--------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 | methods: { ...mapMutations(['add', 'reduce']), ...mapActions({ addOdd: 'addOdd', addWait: 'addWait' }), }, |

生成的方法长这样,需要传入一个value

|---------------|--------------------------------------------------------| | 1 2 3 | add(value){ this.$store.commit('add', value) } |

所以调用时就需要手动传入 value

|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 | <!-- 手动传入加数num --> <button @click="add(num)">+</button> <button @click="reduce(num)">-</button> <button @click="addOdd(num)">当前总和是奇数再加</button> <button @click="addWait(num)">延迟1s再加</button> |

Vuex模块化 {#Vuex模块化}

不同的功能会用到不同的数据,当很多实现不同功能的数据都写在一个 index.js 中或一个配置项中时,会导致命名冲突且代码不易维护

**作用:**让代码更好维护,让多种数据分类更加明确

将不同数据的 store 配置项单独拿出,每个模块的函数获取的数据或上下文都是模块自己的,无需再指定,即模块的局部状态 /store/count.js

|---------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | export default { // 开启命名空间 namespaced: true, actions: { // context:上下文,一个mini都store,有store中的部分属性和方法 // value,组件中dispatch()传过来的值 addOdd(context, value) { if (context.state.sum % 2) { context.commit('add', value); } }, addWait(context, value) { setTimeout(() => { context.commit('add', value); }, 1000) } }, mutations: { // mutations中的函数收到两个参数 // state:store中的数据,value:commit()传过来的值 add(state, value) { state.sum += value; }, reduce(state, value) { state.sum -= value; }, }, state: { sum: 0, }, getters: { bigSum(state) { return state.sum * 10; } } } |

通过 Store()modules 配置项使用模块 /store/index.js

|------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import Vue from 'vue'; import Vuex from 'vuex'; // 使用vuex插件 Vue.use(Vuex); // 导入求和案例配置 import count from "./count.js"; // 创建store实例 export default new Vuex.Store({ modules: { // 使用模块 count, } }); |

调整 mapState()mapGetters() 等的参数,指定是触发哪个模块的 actionsmutations

|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | computed: { ...mapState('count',['sum']), ...mapGetters('count',['bigSum']) }, methods: { ...mapMutations('count',['add', 'reduce']), ...mapActions('count',['addOdd', 'addWait']), }, |

总结:
(1) 命名空间: 默认情况下,模块内部的 action、mutation 和 getter 注册在全局命名空间,这样使得多个模块能够对同一个 mutation 或 action 作出响应。如果希望模块具有更高的封装度和复用性,可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

(2) 开启命名空间后:

  1. 组件中读取 state 数据

    |-----------------|------------------------------------------------------------------------------------------| | 1 2 3 4 | // 方式一:直接读取 this.$store.count.sum // 方式二:借助mapState ...mapState('count',['sum']) |

  2. 组件中读取 getters 数据

    |-----------------|---------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | // 方式一:直接读取 this.$store.getters['count/bigSum'] // 方式二:借助mapGetters ...mapGetters('count',['bigSum']) |

  3. 组件中调用 dispatch

    |-----------------|-----------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | // 方式一:直接读取 this.$store.dispatch('count/addOdd', value) // 方式二:借助mapActions ...mapActions('count',['addOdd', 'addWait']), |

  4. 组件中调用 commit

    |-----------------|----------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | // 方式一:直接读取 this.$store.commit('count/add', value) // 方式二:借助mapActions ...mapMutations('count',['add', 'reduce']), |

赞(0)
未经允许不得转载:工具盒子 » Vue笔记[四]-动画、Vuex