Learning Vue 读书笔记 Chapter 3
3.1 Vue 单文件组件结构(SFC)
3.1.1 结构
<template>
<h2 class="heading">I am a a Vue component</h2>
</template>
<script lang="ts">
export default { name: 'MyFistComponent', };
</script>
<style>
.heading { font-size: 16px; }
</style>
3.1.2 重构非SFC
3.2 Vue 中使用 defineComponent() 实现 TypeScript 支持
3.2.1 定义:
defineComponent()
方法是一个包装函数,它接受一个配置对象,并返回带有类型推断的相同内容,用于定义一个组件。(defineComponent()
方法仅在 Vue 3.x 及以上版本中可用,并且只有在需要使用 TypeScript 时才会相关。)
3.3 组件生命周期钩子
3.3.1 生命周期
生命周期钩子 | 使用场景 |
---|---|
beforeCreate | 当需要在修改组件数据之前加载外部逻辑时使用。 |
created | 当需要将外部数据加载到组件中时使用。此钩子比 mounted 更适合从外部资源读取或写入数据。 |
mounted | 当需要执行任何 DOM 操作或访问组件的 DOM 节点时使用。 |
3.3.2 setup
setup
是组件生命周期开始之前的第一个事件钩子。该钩子在 Vue 实例化组件之前运行一次。在此阶段,组件实例尚未创建,因此无法访问 this
:
export default {
setup() {
console.log('setup hook');
console.log(this); // undefined
}
}
setup()
返回一个对象,该对象包含对组件内部响应式状态、方法以及任何静态数据的所有引用。如果你使用 <script setup>
,则无需手动返回任何内容。在这种情况下,Vue 会在编译期间自动将此语法中声明的所有变量和函数转换为适当的 setup()
返回对象。然后,你可以通过 this
关键字在模板或组件选项对象的其他部分访问它们。
<script setup lang='ts'>
const message = 'Welcome to Vue 3!'
</script>
使用 <script setup>
而不是 setup()
的一个显著优点是它内置了对 TypeScript 的支持。因此,不再需要 defineComponent()
,编写组件所需的代码量也更少。
需要注意的是,这里的 message
不是响应式数据。要使其成为响应式数据,必须使用 Composition API 中的 ref()
函数对其进行包装。
3.3.3 理解Ref
ref
是 Vue 内置的一个属性,允许你直接引用 DOM 元素或已挂载的子组件实例。在模板部分,你可以将 ref
属性的值设置为一个字符串,该字符串代表目标元素上的引用名称。
<template>
<div>
<input type="text" ref="messageRef" placeholder="输入消息" />
</div>
</template>
然后,你可以在脚本部分通过 this.$refs.messageRef
实例访问 messageRef
,从而操作输入元素。引用实例 messageRef
将拥有输入元素的所有属性和方法。(注意:ref
属性只有在组件挂载之后才能访问。)
在使用 v-for
循环元素时,如果你在这些元素上使用 ref
属性,引用实例将是一个包含所有循环元素的数组,且这些元素没有特定的顺序。
3.3.4 局部样式组件
类似于常规的 HTML 页面结构,我们可以使用 <style>
标签为 SFC(单文件组件)定义 CSS 样式:
<style>
h1 {
color: red;
}
</style>
在 Vue SFC 组件的结构中,<style>
部分通常位于最后,并且可以出现多次。当组件挂载到 DOM 时,Vue 引擎会将 <style>
标签中定义的 CSS 样式应用到应用程序中的所有元素或匹配的 DOM 选择器。换句话说,组件中 <style>
里出现的所有 CSS 规则在挂载后会全局生效。
使用 <style scoped>
标签时,Vue 会确保 CSS 规则仅应用于组件内的相关元素,而不会泄漏到应用程序的其他部分。Vue 通过以下步骤实现这一机制:
- 为目标元素标签添加一个随机生成的数据属性,属性名称以
data-v-
为前缀。 - 转换
<style scoped>
标签中定义的 CSS 选择器,使其包含生成的数据属性。
从 Vue 3.x 开始,您可以使用 :deep()
伪类在父组件中通过作用域样式(scoped style)覆盖或扩展子组件的样式。例如,我们可以从父组件 App
中覆盖子组件 HeadingComponent
中段落元素 p
的作用域样式。
<!-- App.vue -->
<template>
<section class="wrapper">
<HeadingComponent />
<span class="heading">This is a span element in App.vue component</span>
</section>
</template>
<style scoped>
.wrapper :deep(p) {
color: #000;
}
</style>