前言
虽然Vue3
出来很久并且非常成熟了,但市面上的Vue
项目中Vue2
依然还是占半壁江山的。小弟当年刚入行时接触就是Vue2
项目,后来Vue3
流行之后慢慢开始在Vue3
和Vue2
项目中反复穿插。因此想通过整合最简单易懂的事例全面总结一下Vue2
的传参方式。
先直入主题列出有哪些传参方式,下面再通过事例一一讲解。
props
(父传子)$emit
与v-on
(子传父)EventBus
(兄弟传参).sync
与update:
(父子双向)v-model
(父子双向)ref
$children
与$parent
$attrs
与$listeners
(爷孙双向)provide
与inject
(多层传参)Vuex
(全局)Vue.prototype
(全局)- 路由
- 浏览器缓存 (全局)
window
(全局)$root
(顶层)slot
(父传子)
一、props(父传子)
思路简述:父组件直接用冒号
:
绑定变量,然后子组件通过props
接收父组件传过来的内容。
父组件代码: 核心代码在第3
行,直接用:message="message"
传参。
子组件代码: 用props
接收消息后可以直接使用,如下第3
行和第16
行中直接使用
注意: props
有两种接收方法,如下第9
行注释的就是简写用法,此用法不能设置默认值。
注意: 此传参方式是单向的,即子组件接收到父组件的数据后,是不能直接修改props
接收的数据,否则会直接报错。
二、$emit与v-on (子传父)
思路简述: 子组件通过
$emit
触发父组件的指定方法并且在此方法中携带任意参数,父组件通过在被触发的方法中拿到携带的参数完成子传父。语法:
$emit(方法名,参数)
子组件代码: 核心代码在第11
行,触发方法并且携带参数。
父组件代码: 核心代码在第3
行触发事件,获取到子组件的传参。
三、EventBus (兄弟传参)
思路简述: 先创建一个全局的事件总线
Bus
(可以随意命名),并挂载在Vue.prototype
上。然后兄弟组件
A
通过$emit
发送参数,兄弟组件B
通过$on
接收参数。
- 有两种使用方法,下面分别讲解。
方法一: 直接挂载全局事件总线,全局直接使用不需要额外引入。
- 先在项目的入口文件中(
main.js
或main.ts
)创建全局事件Bus
并且挂载在Vue.prototype
*
兄弟组件A
代码: 通过this.$Bus.$emit(方法名,参数)
发送参数。
兄弟组件B
代码: 通过this.$Bus.$on(对应$emit的方法,本地方法)
触发本地的方法,从而接收参数。
注意: 如上第10-12
行所示,在组件销毁前要在 beforeDestroy
生命周期中使用$off
移除移除$on
的事件监听器,防止避免内存泄漏影响性能。如下所示
方法二: 不创建全局事件总线,单独开一个文件,哪里需要就哪里引用。
- 创建一个单独文件命名为
Bus.js
(可以自由命名)
兄弟组件A
代码: 先引入Bus.js
文件,然后通过Bus.$emit(方法名,参数)
发送参数。
兄弟组件B
代码: 先引入Bus.js
文件,然后通过Bus.$on(对应$emit的方法,本地方法)
触发本地的方法,从而接收参数。同样也需要使用$off
销毁事件监听。
四、.sync与update: (父子双向)
思路简述:
.sync
其实是一个语法糖, 配合子组件用this.$emit('update:绑定的属性名', 方法)
修改父组件属性, 能解决props
只能单向传递的问题。
父组件代码: 核心代码在第3行,比普通的父传子多使用了.sync
修饰符。
子组件代码: 核心代码是第14
行,通过this.$emit
同步修改父组件内容。
注意: 使用.sync
修饰符时,this.$emit
里面总是以 update:
开头,后面接要修改的属性名称。
五、v-model (父子双向)
思路简述:v-model
最常用于表单,它其实是一个语法糖,并且和上面.sync
有点类似。v-model
本质上是v-bind:value
和@input
组件效果。通过v-bind:value
绑定数据父传子,通过@input
触发对应事件子传父从而实现双向绑定。
父组件代码: 直接用v-model
绑定要传给子组件的参数,当子组件触发 input
事件时父组件myData
会同步更新。
子组件代码: 当input
输入框的内容发生变化时,就会触发 @input
事件,然后this.$emit
同步修改父组件的值。
注意: 在子组件当中,必须要定义model
来指定 props
和事件名称(名称默认为 input
)。
六、ref
思路讲解: ref
主要用来访问子组件的方法和属性,是直接操纵DOM
的方式。主要用法是在子组件上绑定一个ref
,然后父组件用this.$refs
直接访问子组件的方法。
父组件代码: 子组件上用ref="refChild"
绑定一个ref
,然后用this.$refs.refChild
获取到子组件实例,能获取到子组件属性和操纵子组件方法。
子组件代码:
七、$children与$parent
简述: $children
和 $parent
是Vue
用于访问子组件实例和父组件实例的特殊属性。其中$children
能获取所有子组件实例但不能获取孙子的,而$parent
获取当前组件的父组件实例。
父组件代码: 直接使用this.$children
即可获取。
注意: 获取到的实例可能为空,因此需要判空。并且如果有多个子组件时返回的是一个数组,所以需要通过下标确认对应的子组件数据。
子组件代码: 类似地,父组件也是同样用法,但区别是返回的不是数组而且一个对象,能直接使用。
八、$attrs与$listeners (爷孙双向)
简述: $attrs
和 $listeners
相当于是使用在父亲组件上的一个中转站。 $attrs
用于将props
外的数据从爷组件传递给孙组件的,而$listeners
用于从孙组件中触发爷组件中事件达到传参效果。
下面把$attrs
与$listeners
分开讲解更易于理解。
$attrs使用流程代码:
(1)爷组件代码: 类似父传子,正常用冒号:
绑定属性传参。
(2)父组件代码: $attrs
作用在父组件,意思是把props
之外属性全部传递给到孙子。
注意:如果这里父组件用
props
接收了name
属性,那么用$attrs
无法传递到孙子组件,因为只能传递props
之外属性。
(3)孙组件代码:类似父传子,正常用popos
接收爷组件传过来的参数。
$listeners使用流程代码:
(1)孙组件代码 直接this.$emit
类似子传父
(2)父组件代码: $listeners
作用在父组件。
(3)爷组件代码: 类似子传父中的父组件,触发对应孙子组件this.$emit
中的my-event
事件接收到参数。
这里感觉算两种(爷传孙与孙传爷)传参方式了,但由于都是类似中转站效果,所以放一起说比较好理解。
九、provide与inject (多层传参)
简述: provide
与inject
无论多少层组件都能传参。顶层组件通过provide
传参,下面所有组件都能用inject
接收,而且子组件也能通过方法给顶层组件传参。
顶层组件代码: 核心代码在第8
行的provide()
中,可以传递常量、变量和方法。
子孙组件代码: 核心代码在第10
行接收参数, 除了能接收顶层参数外,还能通过参考第13
行的用法,通过顶层给到的方法传参给顶层组件。
十、Vuex (全局)
有针对性写过对应的文章,可以直接跳转细看: 对比学习vuex和pinia用法
十一、Vue.prototype (全局)
简述:能用Vue.prototype
把任何属性和方法挂载在Vue
实例了,让所有Vue
实例共用。
(1)挂载属性 直接往Vue.prototype
挂载即可
(2)挂载方法 直接往Vue.prototype
挂载即可
调用: 直接在任何页面用this
调用
十二、浏览器缓存
简述: localStorage
和sessionStorage
:主要是浏览器用来持久化存储的,这算是用的不多,但也是必用的一种通信方式。两者区别如下
sessionStorage
(临时存储):最大空间5M
,为每一个数据源维持一个存储区域,但只在浏览器打开期间存在,关闭后数据会不会消失,包括页面重新加载。
localStorage
(长期存储):最大空间5M
,与 sessionStorage 一样,但是哪怕浏览器关闭后,数据依然会一直存在,除非手动删除。
具体用法如下所示:
注意: 存储的数据只能是字符串形式,因此如果要存储对象或者数组,则需要使用 JSON.stringify
来转换后再存储,读取后用 JSON.parse
还原。
十三、window (全局)
简述: 直接用语法 window.age = '18'
定义然后全局
通用即可。(此方式是存放在内存刷新会清空)
注意:在 Vue
应用中,虽然可以直接将属性挂载到 window
对象上实现全局通用,但并推荐,因为这可能会出现命名冲突、导致代码难以维护
。
添加属性和方法:直接定义,可以是属性也可以是对象
使用:
十四、路由
简述: Vue
在路由跳转时携带参数其实也很常用的方式,下面汇总一下三种路由传参。
(1)通过 params
传参 跳转页面用法:
目标页面接收参数:
(2)通过 query
传参
跳转页面用法:有几种方式
目标页面接收参数:
(3)通过动态路由传参
注意: 如果用动态路由传参需要对路由进行配置;并且参数会在 url
中显示。 如下所示,在path
后面要配置:name/:age
.
跳转页面用法:
目标页面接收参数:
十五、$root (顶层)
简述: 可以通过 $root
访问到整个 Vue
树的根实例,也就是可以使用 $root
来访问全局的属性或者修改全局的属性。
示例:在main.js
文件中定义一个globalName
属性,可以全局使用。
在下层任意组件使用或者修改内容
十六、slot(父传子)
简述: 通过插槽也是可以传递参数,这也是很多人忽略的一种方式。父组件可以通过插槽向子组件传递参数,然后子组件拿到参数进行渲染。
下面主要讲解具名插槽和默认插槽两种使用方式。
(1)具名插槽用法
子组件代码: 用slot
定义一个名叫header
的插槽。
父组件代码: 用v-slot:header
向子组件的header
插槽传递内容。这边传递什么那边就会在对应区域显示什么。
(2)无参数传递的默认插槽
子组件代码: 用slot
定义插槽时不需要指定name
名称。
父组件代码: 不需要指定插槽名称,只要在组件中间填写内容就会渲染在默认插槽中。