Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

My Blog

从此烟雨落金城,一人撑伞两人行。

组件基础

定义一个组件

将 Vue 组件定义在一个单独的 .vue 文件中,这被叫做单文件组件 (简称 SFC)

1
2
3
4
5
6
7
8
9
<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

<template>
<button @click="count++">You clicked me {{ count }} times.</button>
</template>

使用一个组件

要使用一个子组件,我们需要在父组件中导入它。这个组件将会以默认导出的形式被暴露给外部。

1
2
3
4
5
6
7
8
<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script>

<template>
<h1>Here is a child component!</h1>
<ButtonCounter />
</template>

通过 <script setup>,导入的组件都在模板中直接可用。

传递props(父-子)

向组件中传递数据,这就会使用到 props。

父组件向子组件传递数据使用子组件使用props。

Props 是一种特别的 attributes,你可以在组件上声明注册。

1
2
3
4
5
6
7
8
<!-- BlogPost.vue -->
<script setup>
defineProps(['title'])
</script>

<template>
<h4>{{ title }}</h4>
</template>

当一个 prop 被注册后,可以像这样以自定义 attribute 的形式传递数据给它:

1
2
3
<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />

defineProps 会返回一个对象,其中包含了可以传递给组件的所有 props:

1
2
const props = defineProps(['title'])
console.log(props.title)

使用 v-bind 来传递动态 prop 值的。

1
2
3
4
5
6
7
8
9
10
11
const posts = ref([
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
])

<BlogPost
v-for="post in posts"
:key="post.id"
:title="post.title"
/>

监听事件(子-父)

子组件使用 $emit 方法向上抛出自定义事件,向父组件传递行为(自定义事件),父组件监听上抛的事件。

1
2
3
<BlogPost
@enlarge-text="postFontSize += 0.1"
/>
1
2
3
4
5
6
7
<!-- BlogPost.vue, 省略了 <script> -->
<template>
<div class="blog-post">
<h4>{{ title }}</h4>
<button @click="$emit('enlarge-text')">Enlarge text</button>
</div>
</template>

当点击按钮之后,抛出的事件会被父组件监听,同时父组件触发该事件并引发行为。

通过 defineEmits 宏来声明需要抛出的事件:

1
2
3
4
5
<!-- BlogPost.vue -->
<script setup>
defineProps(['title'])
defineEmits(['enlarge-text'])
</script>

声明了一个组件可能触发的所有事件,还可以对事件的参数进行验证

返回一个等同于 $emit 方法的 emit 函数。它可以被用于在组件的 <script setup>中抛出事件,因为此处无法直接访问 $emit

1
2
3
4
5
<script setup>
const emit = defineEmits(['enlarge-text'])

emit('enlarge-text')
</script>

插槽分配内容(父-子)

将父组件中的内容会自动替换插槽中的内容。

通过 Vue 的自定义 <slot> 元素来实现:

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div class="alert-box">
<strong>This is an Error for Demo Purposes</strong>
<slot />
</div>
</template>

<style scoped>
.alert-box {
/* ... */
}
</style>

使用 <slot> 作为一个占位符,父组件传递进来的内容就会渲染在这里。

动态组件

当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。

被传给 :is 的值可以是以下几种:

  • 被注册的组件名
  • 导入的组件对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<script setup>
import Home from './Home.vue'
import Posts from './Posts.vue'
import Archive from './Archive.vue'
import { ref } from 'vue'

const currentTab = ref('Home')

const tabs = {
Home,
Posts,
Archive
}
</script>

<template>
<div class="demo">
<button
v-for="(_, tab) in tabs"
:key="tab"
:class="['tab-button', { active: currentTab === tab }]"
@click="currentTab = tab"
>
{{ tab }}
</button>
<component :is="tabs[currentTab]" class="tab"></component>
</div>
</template>

评论