QX-AI
GPT-4
QX-AI初始化中...
暂无预设简介,请点击下方生成AI简介按钮。
介绍自己
生成预设简介
推荐相关文章
生成AI简介
过渡与动画 {#过渡与动画}
Vue 封装了过渡与动画效果
作用: 在插入 、更新 、移除 Dom 元素时,自动在合适的时刻在过渡标签 上添加 或移除不同的类名 ,只需写动画和过渡效果并应用到对应时刻的类名上,而无需手动操作 Dom
过渡标签:
(1) <transition>
包裹需要动画效果的单个 元素
(2) <transition-group>
包裹需要动画效果的多个 元素,每个元素都需要配置 Key 属性
不同时刻样式类名:
(1) 控制元素进入的样式
- v-enter 进入的起点
- v-enter-active 进入过程中
- v-enter-to 进入的终点
(2) 控制元素离开的样式
- v-leave 离开的起点
- v-leave-active 离开过程中
- v-leave-to 离开的终点
过渡标签添加 name 属性来配置类名的前缀 ,默认是 v ,如进入起点的类名是 .v-enter 或 <前缀>-enter
离开和进入: 即元素的插入 、更新 、移除 ,通常配合 v-show 、v-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,刚好拿来用
**功能:**点击登陆提示登陆中,登陆成功提示成功登陆,点击获取账单,提示加载中,请求成功后展示所有账单的列表
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 实例上,本质都是对象
- **Actions:**进行一些业务逻辑(异步)的操作,如发送 AJAX 请求,不直接对数据进行操作
- **Mutations:**对数据进行直接的维护,有许多对数据进行操作的自定义方法
- **State:**状态(数据),存放着多个组件共享的数据
Vuex的工作循环:
- 组件通过
dispatch()
调用 Actions 中的方法,触发一些业务逻辑 - Actions 中业务逻辑处理完后,在合适时机调用
commit()
触发 Mutations 中对数据进行直接操作的方法 - 然后 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 中
一些总结与注意:
- 虽然
$store.state.xxx = xxx
直接修改数据,也能响应式更新视图,但这样做无法被 vuex-tools 所监视,所以不要直接修改数据 commit()
和dispatch()
都只能传入两个参数,第一个是要触发的函数名,第二个是传入的数据- actions 中的函数收到两个参数,第一个 context 指上下文,是一个 mini 的 store,有部分 store 上的属性和方法,第二个 value 是
dispatch()
传来的数据 - mutations 中的函数也收到两个参数,第一个 state 是 store 中的数据,第二个 value 是
commit()
传来的数据
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'
|
使用注意:
- 传入一个对象,key-value 是
<生成的计算属性名>:<状态名或getter名>
- 返回值是包含多个计算属性的对象,需要用
...
对象展开运算符,将其与组件的计算属性对象合并
|---------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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()
等的参数,指定是触发哪个模块的 actions 或 mutations
|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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) 开启命名空间后:
-
组件中读取 state 数据
|-----------------|------------------------------------------------------------------------------------------| |
1 2 3 4
|// 方式一:直接读取 this.$store.count.sum // 方式二:借助mapState ...mapState('count',['sum'])
| -
组件中读取 getters 数据
|-----------------|---------------------------------------------------------------------------------------------------------------| |
1 2 3 4
|// 方式一:直接读取 this.$store.getters['count/bigSum'] // 方式二:借助mapGetters ...mapGetters('count',['bigSum'])
| -
组件中调用 dispatch
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------| |
1 2 3 4
|// 方式一:直接读取 this.$store.dispatch('count/addOdd', value) // 方式二:借助mapActions ...mapActions('count',['addOdd', 'addWait']),
| -
组件中调用 commit
|-----------------|----------------------------------------------------------------------------------------------------------------------------| |
1 2 3 4
|// 方式一:直接读取 this.$store.commit('count/add', value) // 方式二:借助mapActions ...mapMutations('count',['add', 'reduce']),
|