【三十天精通Vue 3】 第三天 Vue 3的组件详解
✅创作者:陈书予
🎉个人主页:陈书予的个人主页
🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区
🌟专栏地址: 三十天精通 Vue 3
文章目录
- 引言
- 一、Vue 3 组件的概述
- 1. Vue 3 的组件系统
- 2. Vue 3 组件的特点
- 二、组件的基本语法
- 1. Vue 3 组件的实例结构
- 2. Vue 3 组件的指令
- 3. Vue 3 组件的生命周期
- 生命周期图示
- 三、组件的模板和数据
- 1. 组件的模板语法
- 2. 组件的数据传递
- 3. 组件的嵌套
- 四、组件的事件与响应
- 1. 组件的事件机制
- 2. 组件的响应式系统
- 3. 组件的发布 - 订阅模式
- 五、组件的通信
- 1. 组件之间的数据传递
- 2. 组件之间的通信机制
- 3. Vue 3 的跨组件通信插件
- 六、Vue 3 的虚拟 DOM
- 1. Vue 3 的虚拟 DOM 原理
- 2. Vue 3 的虚拟 DOM 的优势
- 3. Vue 3 的虚拟 DOM 的实现方式
引言
Vue 3 组件是 Vue.js 框架中最重要的概念之一。Vue 3 组件是一个可复用、可组合、可交互的 Vue 实例,它封装了一个特定功能的 UI 界面。在 Vue 3 中,组件的设计和使用都变得更加简单和灵活,使得开发人员能够更加快速地构建复杂的 Web 应用程序。今天,我们将介绍 Vue 3 组件的基本语法、模板和数据、事件与响应、通信以及虚拟 DOM 等方面的内容。
一、Vue 3 组件的概述
1. Vue 3 的组件系统
Vue 3 的组件系统是 Vue.js 3 的核心,它允许开发者将 HTML、CSS 和 JavaScript 组合成可重用的组件。Vue 3 组件的特点包括:
- 可嵌套:组件可以嵌套在一起,形成复杂的 DOM 结构。
- 响应式:组件中的数据可以响应外部事件和数据变化,并更新组件的视图。
- 模板语法:组件可以使用模板语法来描述 DOM 结构,使组件更易于复用和维护。
- 指令:Vue 3 组件支持指令,可以动态修改组件的属性或数据。
2. Vue 3 组件的特点
Vue 3 组件的特点包括:
- 响应式:组件中的数据可以响应外部事件和数据变化,并更新组件的视图。
- 模板语法:组件可以使用模板语法来描述 DOM 结构,使组件更易于复用和维护。
- 指令:Vue 3 组件支持指令,可以动态修改组件的属性或数据。
- 组件通信:不同组件之间可以相互通信,传递数据和事件。
- 虚拟 DOM:Vue 3 使用虚拟 DOM 来提高渲染性能,减少 DOM 操作。
二、组件的基本语法
1. Vue 3 组件的实例结构
在 Vue 3 中,一个组件实例是由一个 Vue 实例构造函数创建的,可以通过 Vue.component 方法来注册组件。下面是一个例子:
// 定义一个组件
const myComponent = {
template: '<div>{{ message }}</div>',
data() {
return {
message: 'Hello, World!'
}
}
};
// 注册组件
Vue.component('my-component', myComponent);
在这个例子中,我们定义了一个名为 myComponent 的组件,它包含一个模板和数据。通过 Vue.component 方法注册这个组件后,就可以在应用程序中使用 <my-component>
标签来渲染这个组件。
2. Vue 3 组件的指令
Vue 3 中的指令是一种特殊的属性,用于在组件中添加动态行为。常用的指令有:
v-bind
:用于绑定元素属性;v-model
:用于绑定表单元素的值;v-if
:用于条件渲染元素;v-show
:用于条件展示元素;v-for
:用于循环渲染元素;v-on
:用于绑定事件监听器;v-bind:prop
:用于绑定组件 prop;v-on:event
:用于组件触发事件;v-slot
:用于插槽;v-html
:用于渲染 HTML 字符串。
下面是这些指令的用法示例:
<!-- v-bind -->
<div v-bind:class="{'active': isActive}"></div>
<!-- v-model -->
<input v-model="message">
<!-- v-if -->
<div v-if="isShown">Hello World!</div>
<!-- v-show -->
<div v-show="isShown">Hello World!</div>
<!-- v-for -->
<div v-for="item in items">{{ item }}</div>
<!-- v-on -->
<button v-on:click="doSomething">Click me</button>
<!-- v-bind:prop -->
<my-component v-bind:title="title"></my-component>
<!-- v-on:event -->
<my-component v-on:custom-event="handleCustomEvent"></my-component>
<!-- v-slot -->
<my-component>
<template v-slot:default> Some content </template>
</my-component>
<!-- v-html -->
<div v-html="htmlString"></div>
3. Vue 3 组件的生命周期
在 Vue 3 中,组件的生命周期是指组件实例从创建到销毁期间所经过的一系列过程,包括了组件实例的创建、挂载、更新和销毁等过程。Vue 3 组件的生命周期钩子函数可以让我们在不同阶段对组件进行操作和处理,例如初始化数据、挂载 DOM、监听事件等。
生命周期图示
Vue 3 的组件生命周期与 Vue 2 有所不同,以下是 Vue 3 组件生命周期的详细说明:
- beforeCreate:实例刚被创建出来,此时组件的属性和方法都还没有被初始化,不能访问 data、props、methods 等数据。
- created:实例已经被创建出来,数据已经初始化好了,可以访问 data、props、methods 等数据,但是$el 属性还没有被创建,还不能访问 DOM 节点。
- beforeMount:在挂载开始之前被调用,相关的 render 函数首次被调用,此时 render 函数得到的 DOM 节点还没有被渲染到页面上。
- mounted:组件挂载完成之后被调用,相关的 render 函数最后一次被调用,此时 render 函数得到的 DOM 节点已经被渲染到页面上了。
- beforeUpdate:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
- updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁完成之后被调用。
- beforeDestroy:实例销毁之前被调用,此时组件实例仍然完全可用,可以访问 data、methods 等数据。
- destroyed:实例销毁之后被调用,此时组件实例已经被完全销毁,无法访问 data、methods 等数据。
此外,还有一个被废弃的生命周期是 beforeMount、mounted 和 beforeUpdate、updated,这些生命周期被废弃是因为 Vue 3 中使用 render 函数时不需要关心 DOM 节点的渲染过程,因此这些生命周期的调用时机已经不再重要。
三、组件的模板和数据
1. 组件的模板语法
Vue 3 组件的模板语法采用了类似 HTML 的标记语言,用于描述组件的外观和行为。Vue 3 的模板语法主要由以下几个部分组成:
- 插值表达式:用于在模板中插入变量值、表达式或计算结果。
- 指令:用于在模板中绑定变量、控制元素的显示或隐藏、循环渲染列表等。
- 事件绑定:用于在模板中绑定事件处理函数。
下面我们通过一个简单的示例来说明 Vue 3 的模板语法:
<template>
<div>
<h1>{{ title }}</h1>
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
<button @click="handleClick">点击</button>
</div>
</template>
<script>
export default {
name: 'MyComponent',
data() {
return {
title: '我的组件',
items: [
{ id: 1, name: '选项一' },
{ id: 2, name: '选项二' },
{ id: 3, name: '选项三' },
],
};
},
methods: {
handleClick() {
console.log('按钮被点击了!');
},
},
};
</script>
在上面的示例中,我们定义了一个名为 MyComponent 的组件,它包含了一个标题、一个列表和一个按钮。在模板中,我们使用了插值表达式来展示标题和列表项的名称,使用 v-for 指令循环渲染了列表,并使用 @click 事件绑定来绑定按钮的点击事件。
2. 组件的数据传递
在 Vue 3 中,组件之间的数据传递可以通过 props 和 events 进行。
- Props
props 是组件之间传递数据的主要方式。在父组件中,可以通过 props 将数据传递给子组件。子组件可以通过接收 props 来获取父组件传递的数据。下面是一个简单的示例:
// 父组件
export default {
name: 'ParentComponent',
props: {
childData: {
type: String,
default: ''
}
},
data() {
return {
counter: 0
};
},
mounted() {
this.$nextTick(() => {
this.childData = this.childData || 'default value';
});
}
};
// 子组件
export default {
name: 'ChildComponent',
props: {
childData: {
type: String,
default: ''
}
},
template: `
<div>
<p>{{ childData }}</p>
</div>
`
};
在上面的示例中,父组件 ParentComponent
可以通过 props 将数据传递给子组件 ChildComponent
。子组件 ChildComponent
通过接收 props 来获取父组件传递的数据。在子组件中,我们可以通过 $nextTick
方法在组件挂载后更新 props 的值。
- Events
除了 props,组件之间还可以使用 events 进行数据传递。在父组件中,可以通过发布事件将数据传递给子组件。子组件可以通过订阅事件来获取父组件传递的数据。下面是一个简单的示例:
// 父组件
export default {
name: 'ParentComponent',
events: {
childEvent: {
type: 'child-event',
data: {}
}
},
data() {
return {
counter: 0
};
},
mounted() {
this.$nextTick(() => {
this.childEvent({ data: 'child event data' });
});
}
};
// 子组件
export default {
name: 'ChildComponent',
setup() {
const childEvent = (data) => {
this.dispatchEvent(new Event('child-event', { data }));
};
return {
childEvent
};
}
};
在上面的示例中,父组件 ParentComponent
发布了一个事件 childEvent
,该事件包含一个数据对象。子组件 ChildComponent
通过 setup
函数中的 childEvent
方法订阅了这个事件,并在事件触发时执行相应的方法。在子组件中,我们可以通过 dispatchEvent
方法在触发事件时执行方法。
3. 组件的嵌套
在 Vue 3 中,组件的嵌套是一种常见的组件设计模式。组件嵌套可以提高组件的复用性和可维护性,同时也可以让组件更好地处理自己的状态和行为。下面是一个简单的组件嵌套示例:
// 父组件
export default {
name: 'ParentComponent',
data() {
return {
children: [
{
name: 'Child1',
component: require('./Child1.vue')
},
{
name: 'Child2',
component: require('./Child2.vue')
}
]
};
},
mounted() {
// 监听子组件更新
this.$nextTick(() => {
this.children.forEach((child) => {
child.component.update();
});
});
}
};
// 子组件
export default {
name: 'Child1',
props: {
name: {
type: String,
default: ''
}
},
template: `
<div>
<h1>{{ name }}</h1>
<Child2Component />
</div>
`
};
export default {
name: 'Child2',
props: {
name: {
type: String,
default: ''
}
},
template: `
<div>
<h1>{{ name }}</h1>
<Child1Component />
</div>
`
};
在上面的示例中,父组件 ParentComponent
包含两个子组件 Child1
和 Child2
。这两个子组件都使用了 Vue 3 的组件嵌套机制,并且都包含了一个 Child2Component
。在父组件中,我们监听了子组件的更新,并在子组件挂载后更新它们的名称。
在子组件 Child1
中,我们使用了 props
来接收父组件传递的数据。在子组件 Child2
中,我们使用了 props
来接收父组件传递的数据,并将其传递给子组件 Child1
。
四、组件的事件与响应
1. 组件的事件机制
在 Vue 3 中,组件可以使用@event 命名约定来触发自定义事件。通过在父组件中使用 v-on 指令来监听这些事件,并在事件处理函数中执行相应的操作。
以下是一个示例:
<template>
<div>
<button @click="handleClick">点击我</button>
</div>
</template>
<script>
export default {
data() {
return {
value: ''
}
},
methods: {
handleClick() {
this.value = '点击了按钮'
}
}
}
</script>
在上面的示例中,我们定义了一个按钮组件,并在按钮的点击事件上使用@click 属性来触发一个自定义事件 handleClick。在父组件中,我们使用 v-on 指令来监听这个事件,并在事件处理函数中更新组件的数据值 value。
<template>
<div>
<child-component @event="handleClick" />
<p>按钮点击事件处理函数执行了:</p>
<template v-if="value">{{ value }}</template>
</div>
</template>
<script>
import ChildComponent from '@/components/ChildComponent.vue'
export default {
components: {
ChildComponent
},
data() {
return {
value: ''
}
},
methods: {
handleClick() {
this.value = '点击了按钮'
}
}
}
</script>
在上面的示例中,我们定义了一个父组件,并在其中使用 v-on 指令来监听 child-component 组件触发的 handleClick 事件。在事件处理函数中,我们更新组件的数据值 value,并在模板中使用 v-if 指令来显示或隐藏一个文本框。
在 Vue 3 中,组件还可以使用@mousedown、@click 等事件来触发自定义事件。同时,组件还可以触发全局事件,例如@load、@error 等。这些事件可以用于异步数据的加载和错误处理。
2. 组件的响应式系统
在 Vue 3 中,组件可以使用响应式系统来管理组件状态。响应式系统使用一个数据列表来跟踪组件状态的变化,并在组件模板中使用 v-model 指令来绑定输入框的值。
以下是一个示例:
<template>
<div>
<input type="text" v-model="inputValue" />
<button @click="handleClick">点击我</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
const inputValue = reactive('')
this.handleClick = () => {
inputValue.push('点击了按钮')
}
return {
inputValue,
handleClick
}
}
}
</script>
在上面的示例中,我们定义了一个文本输入组件和一个按钮组件。我们在输入框中使用 v-model 指令来绑定输入框的值,并在按钮的点击事件上使用@click 属性来触发一个事件。在事件处理函数中,我们使用 push 方法来将一个字符串添加到列表中,以更新组件的状态。
在 Vue 3 中,响应式系统还可以通过@data、@computed、@methods 等属性来管理组件状态。这些属性可以存储和更新组件状态,并使用 v-model 指令来绑定输入框的值。
3. 组件的发布 - 订阅模式
在 Vue 3 中,组件可以使用发布 - 订阅模式来处理事件和响应。发布者发布事件,订阅者订阅事件,当事件发生时,订阅者可以收到通知并执行相应的操作。
下面是一个简单的示例:
// 发布者
export default {
methods: {
incrementCounter() {
this.counter++;
}
},
export default {}
}
// 订阅者
import { incrementCounter } from './Counter';
export default {
name: 'Counter',
data() {
return {
counter: 0
};
},
mounted() {
incrementCounter();
},
methods: {
decrementCounter() {
this.counter--;
}
}
};
在上面的示例中,发布者 Counter
组件发布了一个 increment
事件,订阅者 Counter.vue
组件订阅了这个事件,并在 mounted
生命周期钩子中调用 incrementCounter
方法来触发事件。
在订阅者中,我们通过调用 incrementCounter
方法来触发事件。这个方法可以被看作是发布者的订阅者,因为它接收并处理发布者发布的事件。
五、组件的通信
1. 组件之间的数据传递
在 Vue 3 中,组件之间的数据传递可以通过 props 和 events 进行。props 是主要方式,而 events 可以用于单向数据传递。下面是一个简单的示例:
// 父组件
export default {
name: 'ParentComponent',
props: {
childData: {
type: String,
default: ''
}
},
data() {
return {
counter: 0
};
},
mounted() {
this.$nextTick(() => {
this.childData = this.childData || 'default value';
});
}
};
// 子组件
export default {
name: 'ChildComponent',
props: {
childData: {
type: String,
default: ''
}
},
template: `
<div>
<p>{{ childData }}</p>
</div>
`
};
在上面的示例中,父组件 ParentComponent
可以通过 props 将数据传递给子组件 ChildComponent
。子组件 ChildComponent
通过接收 props 来获取父组件传递的数据。在子组件中,我们可以通过 $nextTick
方法在组件挂载后更新 props 的值。
2. 组件之间的通信机制
在 Vue 3 中,组件之间的通信机制主要包括两个方面:props 和 events。props 是主要方式,而 events 可以用于单向数据传递。下面是一个简单的示例:
// 父组件
export default {
name: 'ParentComponent',
props: {
childData: {
type: String,
default: ''
}
},
data() {
return {
counter: 0
};
},
mounted() {
this.$nextTick(() => {
this.childData = this.childData || 'default value';
});
}
};
// 子组件
export default {
name: 'ChildComponent',
props: {
childData: {
type: String,
default: ''
}
},
template: `
<div>
<p>{{ childData }}</p>
</div>
`
};
在上面的示例中,父组件 ParentComponent
可以通过 props 将数据传递给子组件 ChildComponent
。子组件 ChildComponent
通过接收 props 来获取父组件传递的数据。在子组件中,我们可以通过 $nextTick
方法在组件挂载后更新 props 的值。
3. Vue 3 的跨组件通信插件
Vue 3 的跨组件通信插件主要有 two-way data binding、computed properties、watch 和 events。下面是一个简单的示例:
// 父组件
export default {
name: 'ParentComponent',
data() {
return {
counter: 0
};
},
methods: {
incrementCounter() {
this.counter++;
}
}
};
// 子组件
export default {
name: 'ChildComponent',
props: {
value: {
type: Number,
default: 0
}
},
template: `
<div>
<p>{{ value }}</p>
<button @click="increment">Click me</button>
</div>
`
};
在上面的示例中,父组件 ParentComponent
可以通过 two-way data binding 将子组件 ChildComponent
的值与父组件的变量进行绑定。子组件 ChildComponent
通过 props 接收父组件传递的值。在子组件中,我们可以通过 @click
事件监听器触发父组件的方法 incrementCounter
。
六、Vue 3 的虚拟 DOM
1. Vue 3 的虚拟 DOM 原理
在 Vue 2 中,Vue 使用真实的 DOM 来管理组件的渲染。当组件更新时,Vue 会遍历组件中的所有子组件,然后根据新的数据重新渲染它们。这种方式称为“块状渲染”。
在 Vue 3 中,Vue 使用了一种新的渲染方式,称为“响应式渲染”。Vue 3 中的虚拟 DOM 是一种轻量级的 DOM 表示形式,它只包含已经被更新的部分。当 Vue 发现组件的数据发生了变化时,它会将虚拟 DOM 重新渲染为真实 DOM。
虚拟 DOM 是 Vue 3 中的一个重要概念,它使得 Vue 3 的渲染性能得到了极大的提升。虚拟 DOM 具有以下特点:
- 虚拟 DOM 是轻量级的,它只包含已经被更新的部分,因此不会对性能产生太大影响。
- 虚拟 DOM 可以动态添加、删除和修改组件,这使得 Vue 的渲染性能得到了极大的提升。
- 虚拟 DOM 支持数据绑定和事件处理,这使得组件之间的交互变得更加简单和高效。
2. Vue 3 的虚拟 DOM 的优势
Vue 3 的虚拟 DOM 相比 Vue 2 的真实 DOM 具有以下优势:
- 性能更高:虚拟 DOM 减少了 DOM 操作的数量,使得 Vue 的渲染性能得到了极大的提升。
- 更易于维护:虚拟 DOM 使得 Vue 的代码更加清晰和易于维护。
- 灵活性更高:虚拟 DOM 支持动态添加、删除和修改组件,这使得 Vue 的渲染性能得到了极大的提升,同时也使得组件之间的交互变得更加简单和高效。
3. Vue 3 的虚拟 DOM 的实现方式
在 Vue 3 中,虚拟 DOM 是由 Vue 自己创建和维护的。当一个组件更新时,Vue 会创建一个新的虚拟 DOM,然后根据新的数据重新渲染为真实 DOM。
虚拟 DOM 的实现方式包括以下几个方面:
- 虚拟 DOM 的渲染:Vue 会遍历组件中的所有子组件,然后根据新的数据重新渲染它们。Vue 使用了自己的渲染函数,可以将虚拟 DOM 转换为真实 DOM。
- 真实 DOM 的构建:Vue 使用了自己的构建函数,可以将虚拟 DOM 转换为真实 DOM。Vue 的构建函数会将虚拟 DOM 中的每个节点和属性转换为真实 DOM 中的对应节点和属性。
- 虚拟 DOM 的比较:当 Vue 发现组件的数据发生了变化时,它会将虚拟 DOM 重新渲染为真实 DOM。在比较虚拟 DOM 和真实 DOM 的差异时,Vue 使用了基于 DOM 操作的比较算法,这使得虚拟 DOM 的比较更加高效。