Vue 的组件可以按两种不同的风格书写:选项式 API 和组合式 API。选项式 API 是在组合式 API 的基础上实现的!关于 Vue 的基础概念和知识在它们之间都是通用的。
在生产项目中:
① 当你不需要使用构建工具,或者打算主要在低复杂度的场景中使用 Vue,例如渐进增强的应用场景,推荐采用选项式 API。
② 当你打算用 Vue 构建完整的单页应用,推荐采用组合式 API + 单文件组件。
本文使用“选项式API”风格进行讲解。
一、组件基础(选项式API风格)
1、定义一个组件并使用
1)当使用构建步骤时,我们一般会将 Vue 组件定义在一个单独的 .vue
文件中,这被叫做 单文件组件 (简称 SFC)。
2)组件名官方推荐使用PascalCase命名规则,如:<PascalCase />
;但是,PascalCase 的标签名在 DOM 模板中是不可用的。为了方便,Vue 支持将模板中使用 kebab-case 的标签解析为使用 PascalCase 注册的组件。这意味着一个以 MyComponent
为名注册的组件,在模板中可以通过 <MyComponent>
或 <my-component>
引用。
Test.vue文件:
或者使用内联js创建:
2)使用组件
① 在 components
选项上注册;
② 使用标签;
2、声明响应式变量的区域data
选用选项式 API 时,会用 data
选项来声明组件的响应式状态。如下:
注:
① Vue 在组件实例上暴露的内置 API 使用 $
作为前缀。它同时也为内部属性保留 _
前缀。因此,你应该避免在顶层 data
上使用任何以这些字符作前缀的属性。
② 在上面的示例中,当你在赋值后再访问 this.someObject
,此值已经是原来的 newObject
的一个响应式代理。与 Vue 2 不同的是,这里原始的 newObject
不会变为响应式:请确保始终通过 this
来访问响应式状态。
3、声明方法的区域methods
注:如上面的示例,Vue 自动为 methods
中的方法绑定了永远指向组件实例的 this
。这确保了方法在作为事件监听器或回调函数时始终保持正确的 this
。你不应该在定义 methods
时使用箭头函数,因为箭头函数没有自己的 this
上下文。
4、组件间传值props与$emit、events
props
:接收父类的值
①props
可以是基础类型(propA: Number
)、数组(props: ['foo']
)或对象类型(props:{ title: String, likes: Number}
),也可以声明允许多种类型 props: {
disabled: [Boolean, Number] }
;设置默认值使用default
、必传约束required
(默认不需要必穿)、校验使用validator
,示例如下:
props
示例:
BlogPost.vue
使用
$emit
:用来调用父组件的方法并传递数据
① 组件通过$emit
触发父类的事件,父组件通过v-on(简写为@)
来监听子组件的触发。
模板表达式中创建emit
:<button @click="$emit('someEvent')">click me</button>
,或者js中methods: { submit() { this.$emit('someEvent') } }
。(注:事件的名称支持自动的格式转换,camelCase形式 -> kebab-case 形式
)。
声明式创建emit
:
② 同样,组件的事件监听器也支持 .once
修饰符:<MyComponent @some-event.once="callback" />
$emit
示例:
BlogPost.vue
App.vue
$emit
添加参数
触发
监听:
⑤ 添加校验:
this.$emit
events
:用来声明需要抛出的方法或变量
5、理解DOM 更新机制-访问更新后的DOM
当你更改响应式状态后,DOM 会自动更新。然而,你得注意 DOM 的更新并不是同步的。相反,Vue 将缓冲它们直到更新周期的 “下个时机” 以确保无论你进行了多少次状态更改,每个组件都只更新一次。
若要等待一个状态改变后的 DOM 更新完成,你可以使用 nextTick() 这个全局 API:
6、理解浅层作用形式-使响应式变量的子项不具备响应式属性
在 Vue 中,状态都是默认深层响应式的。这意味着响应式变量的“子项”及“子项的子项”具有响应式。Vue也提供了创建“ 浅层响应式对象”的方法shallowReactive()
,可使“变量子项的子项”不具备响应式:
7、阻止短期内响应事件重复触发1-Vue防抖_按钮最后一次响应再执行事件
① 在methods
中创建一个执行方法,如下面示例中的click()
;
② 在组件创建事件created
中设置一个“预置防抖的处理函数”(如:debouncedClick
)关联到执行方法(如:click()
);
③ 在组件创建销毁事件unmounted()
中定义“预置防抖的处理函数”的卸载事件(如:this.debouncedClick.cancel()
)。
8、阻止短期内响应事件重复触发2-Vue节流_按钮第一次响应后一定时间内不会再执行事件
略
二、组件样式绑定
1、绑定静态样式
2、动态绑定样式_组件内(在组件内给组件内的元素绑定样式)
1)只启用/关闭样式;支持数组
2)在js中创建样式内容
3)与 计算属性一起使用
3、动态绑定样式_组件外(在组件外给组件内的元素绑定样式)
1)静态绑定
2)动态绑定
3)指定哪个根元素来接收这个样式 :class="$attrs.class"
4、使用内联样式style
1) CSS写法_Vue内置的camelCase写法,如下面示例中的color
与fontSize
:
2)CSS写法_CSS 中的实际名称写法:
3)绑定内联样式与内联样式数组
4):style支持对一个样式属性提供多个值,以解决某个浏览器需要加浏览器特殊前缀才能正常渲染的问题:
注:数组仅会渲染浏览器支持的最后一个值。在这个示例中,在支持不需要特别前缀的浏览器中都会渲染为 display: flex
。
三、深入组件
1、模板引用ref="input"
虽然 Vue 的声明性渲染模型为你抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。要实现这一点,我们可以使用特殊的 ref
attribute。
① 创建引用标签:<input ref="名称" />
② 访问模板引用:this.$refs.名称
1)v-for
中的模板引用
当在 v-for
中使用模板引用时,相应的引用中包含的值是一个数组(应该注意的是,ref 数组并不保证与源数组相同的顺序)。
2)函数模板引用中使用ref
除了使用字符串值作名字,ref
attribute 还可以绑定为一个函数,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数:
注:注意我们这里需要使用动态的 :ref
绑定才能够传入一个函数。当绑定的元素被卸载时,函数也会被调用一次,此时的 el
参数会是 null
。你当然也可以绑定一个组件方法而不是内联函数。
3)组件上的ref
-基础使用
如果一个子组件使用的是选项式 API ,被引用的组件实例和该子组件的 this
完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,当然也因此,应该只在绝对需要时才使用组件引用。大多数情况下,你应该首先使用标准的 props 和 emit 接口来实现父子组件交互。
4)组件上的ref
-限制父类对子组件的访问
下面这个例子中,父组件通过模板引用访问到子组件实例后,仅能访问 publicData
和 publicMethod
2、全局组件
注册全局组件见:Vue3 学习笔记(六)——Vue应用的使用
3、
四、内置组件
1、KeepAlive 组件缓存容器组件
<KeepAlive>
是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例(默认保留组件状态)。语法为<KeepAlive> <component :is="activeComponent" /> </KeepAlive>
示例如下:
CompA.vue
CompB.vue
App.vue
1)保留/排除 对某组件的缓存include
/ exclude
2)设置最大缓存实例数max
3)设置缓存实例的生命周期:当一个组件实例从 DOM 上移除但因为被 <KeepAlive>
缓存而仍作为组件树的一部分时,它将变为不活跃状态而不是被卸载。可以通过 activated 和 deactivated 选项来注册自身的释放。
2、Teleport:将一个组件内部的一部分模板“传送”到该组件的外层位置
适用场景:一个组件模板的一部分在逻辑上从属于该组件,但从整个应用视图的角度来看,它应该被渲染在Vue组件外部的其他地方。比如:弹出自定义窗体,如下:
Modal.vue
App.vue
1)禁用 Teleport方案disabled
;示例如下:
3、Transition:过渡动画组件
它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发:
- 由
v-if
所触发的切换 - 由
v-show
所触发的切换 - 由特殊元素
<component>
切换的动态组件 - 改变特殊的
key
属性
1)基础示例:
2) 组件间过渡
子组件CompA.vue与CompB.vue
父组件
4) 自定义过渡 class
你也可以向 <Transition>
传递以下的 props 来指定自定义的过渡 class:
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
你传入的这些 class 会覆盖相应阶段的默认 class 名。这个功能在你想要在 Vue 的动画机制下集成其他的第三方 CSS 动画库时非常有用,比如 Animate.css:
4、TransitionGroup:v-for
列表中元素变化时的过渡动画组件
<TransitionGroup>
支持和 <Transition>
基本相同的 props、CSS 过渡 class 和 JavaScript 钩子监听器,但有以下几点区别:
- 默认情况下,它不会渲染一个容器元素。但你可以通过传入
tag
prop 来指定一个元素作为容器元素来渲染。 - 过渡模式在这里不可用,因为我们不再是在互斥的元素之间进行切换。
- 列表中的每个元素都必须有一个独一无二的
key
attribute。 - CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。
1) 平滑的进入 / 离开动画
2) 渐进延迟列表动画
5、Suspense:在组件树中协调对异步依赖的处理
它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。
在这个组件树中有多个嵌套组件,要渲染出它们,首先得解析一些异步资源。如果没有 <Suspense>
,则它们每个都需要处理自己的加载、报错和完成状态。在最坏的情况下,我们可能会在页面上看到三个旋转的加载态,在不同的时间显示出内容。有了 <Suspense>
组件后,我们就可以在等待整个多层级组件树中的各个异步依赖获取结果时,在顶层展示出加载中或加载失败的状态。
异步组件默认就是“suspensible”的。这意味着如果组件关系链上有一个 <Suspense>
,那么这个异步组件就会被当作这个 <Suspense>
的一个异步依赖。在这种情况下,加载状态是由 <Suspense>
控制,而该组件自己的加载、报错、延时和超时等选项都将被忽略。
1)基础使用模板
在初始渲染时,<Suspense>
将在内存中渲染其默认的插槽内容。如果在这个过程中遇到任何异步依赖,则会进入挂起状态。在挂起状态期间,展示的是后备内容(#fallback
)。当所有遇到的异步依赖都完成后,<Suspense>
会进入完成状态,并将展示出默认插槽的内容(#default
;如上图<component :is="Component"></component>
)。如果在初次渲染时没有遇到异步依赖,<Suspense>
会直接进入完成状态。
2)异步组件设置timeout
在等待(异步组件)渲染新内容耗时超过 timeout
之后,<Suspense>
将会切换为展示后备内容。若 timeout
值为 0
将导致在替换默认内容时立即显示后备内容。异步组件设置timeout
示例如下:
3)具有的事件
<Suspense>
组件会触发三个事件:pending
、resolve
和 fallback
。pending
事件是在进入挂起状态时触发。resolve
事件是在 default
插槽完成获取新内容时触发。fallback
事件则是在 fallback
插槽的内容显示时触发。
4)错误处理
<Suspense>
组件自身目前还不提供错误处理,不过你可以使用 errorCaptured 选项或者 onErrorCaptured() 钩子,在使用到 <Suspense>
的父组件中捕获和处理异步错误。
五、语法
见:Vue3 学习笔记(八)——Vue语法
六、生命周期
见:Vue3 学习笔记(十)——生命周期
下一章:Vue3 学习笔记(十)——生命周期
作者:꧁执笔小白꧂