组件基础
组件基础
定义一个组件
将 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>
|