Vue组件 - 输入
开始之前
- 需要你对Vue有一定的了解,最好已阅读过一遍官方的教程。
- 包含有Vue3的内容,如果你已熟悉Vue2,但还不熟悉Vue3,也不必感到恐惧。
- 涉及到具体的API使用细节较少。
- 我将Vue组件分成由三部分组成:输入、内部处理、输出(其实可当作一个函数来理解),这篇文章是关于“输入”的内容。
目录
正文
如何理解“输入”
输入,即向组件传值或能导致组件改变的外部因素。这篇文章将组件的所有输入方式进行了分类整理,以便清晰的了解组件的数据来源和改变的外部源。
组件输入的分类
我将输入分成了两类,一是:显式输入,第二个是:隐式输入。下面我将分别介绍这两种分类。
显式输入
显式输入,顾名思义,显式的传给组件的数据。
props
如下所示,利用props
显式的向HelloWorld
组件传入字符串“Welcome to Your Vue.js App”。你几乎可以借助props
向HelloWorld
组件传入任何值,但HelloWorld
组件的内部需要在props
中定义接收的属性名称才行。
<HelloWorld msg="Welcome to Your Vue.js App" />
💡
props
传值是 父级 向 子级 传值方式的一种。- 向
props
传入一个回调函数,也可实现 子级 向 父级 传值。此时,不仅是“输入”也能作为一种“输出”(通过回调函数的参数将值传给 父级)。props
中的default
可理解为函数参数的默认值。type
可理解为函数参数的类型。validator
可理解对函数参数的验证。required
可理解为函数参数是否为可选参数。
总结
emits
"输入"不仅可以是具体的数值,也可以是一个事件(emits)的回调函数。这个事件即包含了HTML
的原生事件,也包括组件自定义的事件。
总结
$attrs
当向组件传入一个未在props
或emits
中定义的 attribute 的时候,Vue会默认把值自动添加到根节点的 attribute 中。如下所示,Date
组件的节点组成:
<template>
<div>
//其它内容
</div>
</template>
我们以如下的方式调用:
<Date class="my-date" />
实际渲染到DOM中的Date组件为:
<div class="my-date">
//Date组件渲染出来的其它DOM
</div>
如上所示,传入的class
添加到了<div>
上。
但,当组件不止有两个根节点的时候(Vue2只允许有一个根节点,而Vue3允许有多个),Vue将怎么处理了?
Vue将选择权交给了你,使用v-bind="$attrs"
将值赋其中任意 一个根 节点。
如果不想要除props
和emits
定义以外的任何值了? 配置:inheritAttrs: false
。
如果根节点不想要,而想给子节点了? 使用v-bind="$attrs"
将值赋其中任意 一个子 节点。
总结
$attrs
属于实例属性,一般用来接收原生HTML
元素的属性。是否被使用,完全由组件内部决定。
💡
$attrs
是 父级 向 子级 传值方式的一种。
slot
在Vue中可借助插槽(slot)来做内容分发,插槽也可以视为组件的一种“输入”。如下所示,Date
组件添加到了HelloWorld
组件的default
插槽中。
<HelloWorld>
<Date msg="Hi" />
</HelloWorld>
💡
- 当向
Date
组件传入msg
的值时,是 祖辈级 向 子孙级 传值方式的一种。- 当是 作用域插槽 时便是 父级 向 子级 传值方式的一种(将
HelloWorld
组件内部的值,传给Date
组件)。
总结
directive
这里主要是指自定义指令。那为什么自定义指令会被认为是一种“输入”了?因为自定义指令可以对组件内的DOM元素进行底层操作,影响着组件的状态。关于组件的更多细节可以查看对应的官方文档。
总结
显式输入总结
下面我来看一个包含所有显式输入的组件使用情况:
- msg为
props
- class为
$attrs
- click为
emits
- v-hour为自定义
directive
- Date和User组件为
slot
,其中User组件通过作用域插槽进行了传值
<HelloWorld msg="Welcome to Your Vue.js App" class="my-hello" @clik="clickFn">
<Date v-hour="time" />
<template v-slot:user="slotProps">
<User :name="slotProps.name" />
</template>
</HelloWorld>
进一步观察,我们可以发现:所有的显式输入基本都需要借助指令来实现!($attrs
除外)
- props借助v-bind
- emits借助v-on
- slot借助v-slot(默认插槽有时可不显式使用)
- 自定义指令就更不用说了,它本身就是个指令
关于v-model
v-model
指令也是组件中常用的输入源,但其本质是props
和emits
的语法糖,所以就不算入“输入”里面了。
隐式输入
隐式输入,是指那些除显式输入之外所有能影响组件状态的情况。他并不“显式”传入,却对组件内部起着影响。
inject
在组件内部通过inject
可以获取祖辈级传入的数据,因为不是一眼就能看到的“输入”,而且还不一定能知道是哪个组件传入的值,所以注入(inject),我将其归类为隐式输入。
总结
mixin
不管是全局混入(mixin)还是只在组件内混入,它都是一种隐式的不易观测的传值和处理方式,所以混入,也被归为隐式输入。
总结
extends
对另一个组件进行扩展(extends),与mixin类似。所以扩展,也是隐式输入的一种。
总结
globalProperties
通过app.config.globalProperties
添加全局属性(property),可让任何组件实例访问;与直接在Vue的原型链上添加类似。因为它是全局属性,是一种“隐式”传值,所以它是隐式输入的一种。
💡
- 是 祖辈级 向 子孙级 传值方式的一种。
总结
隐式输入总结
隐式输入一般用于祖孙级间传值或增加组件的复用性。
输入的总结
最后我们来总结下,“输入”共有哪些:
- 显式输入:
- props
- emits
- $attrs
- slot
- directive
- 隐式输入:
- inject
- mixin
- extend
- globalProperties
最后
- 转载请指明出处
- 不当之处,欢迎交流指正