注册
一个 Vue 组件在使用前需要先被“注册”。
- 全局注册(支持链式调用)
import MyComponent from './App.vue'
app.component('MyComponent', MyComponent)
- 局部注册
<script setup>
import ComponentA from './ComponentA.vue'
</script>
<template>
<ComponentA />
</template>
- 组件名格式
- 注册格式推荐使用
PascalCase - 模板中可以通过
<MyComponent>和<my-component>引用。
props
子组件需要显式声明它所接受的 props
//子组件
<script setup>
const props = defineProps(['foo'])
</script>
<template>
<div> {{foo}}</div>
</template>
props的声明方式除了字符串数组,还有对象的形式
defineProps({
title:String,
count:Number
})
props数据流遵循单向绑定原则,然而当对象或数组作为props被传入时,数据值修改会生效,但是会有很大的性能损耗。
事件
组件模板中直接使用$emit方法
<!--子组件-->
<button @click="$emit('someEvent')">click me</button>
<!--父组件-->
<MyComponent @some-event="callback" />
声明触发组件
<!--子组件-->
<script setup>
const emit = defineEmits(['inFocus', 'submit'])
function buttonClick() {
emit('submit')
}
</script>
<button @click="$emit('someEvent')">click me</button>
<!--父组件-->
<MyComponent @some-event="callback" />
透传Attributes
“透传 attribute”指的是传递给一个组件,却没有被该组件声明为props 或emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。
当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上。多根节点需要显示绑定。
<!--父组件-->
<ComponentA id="aaaa" />
<!--子组件-->
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
插槽
<!--父组件-->
<FancyButton>
Click me! <!-- 插槽内容 -->
</FancyButton>
<!--子组件-->
<button class="fancy-btn">
<slot></slot> <!-- 插槽出口 -->
</button>
<!--渲染结果-->
<button class="fancy-btn">
Click me!
</button>
插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。
- 插槽可以制定默认内容
<button>
<slot>
default message
</slot>
</butto>
- 具名插槽,适用于一个组件内包含多个插槽出口
<!--子组件-BaseLayout->
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
<!--父组件-->
<BaseLayout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<template #default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
- 插槽之间的传参
<!--子组件传参-->
<div>
<slot :text="greetingMessage"></slot>
</div>
当需要接收插槽 props 时,默认插槽和具名插槽的使用方式有一些小区别
<!--默认插槽-->
<MyComponent v-slot="slotProps">
{{ slotProps.text }}
</MyComponent>
<!--v-slot可以使用解构-->
<MyComponent v-slot="{ text }">
{{ text }}
</MyComponent>
<!--具名插槽-->
<MyComponent>
<template #header="headerProps">
{{ headerProps }}
</template>
</MyComponent>
依赖注入
provide和inject的出现就是为了解决prop 逐级透传的问题。一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。
- Provide (提供):为后代提供数据
<script setup>
import { provide } from 'vue'
provide('message', 'hello!')
</script>
第一个参数被称为注入名,第二个参数是提供的值,必须提供值,否则会报错。
一个组件可以多次调用 provide(),使用不同的注入名,注入不同的依赖值。
- inject (注入) : 注入上层组件提供的数据
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
当提供 / 注入响应式的数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中。
- 修改响应式状态
<!--供给方-->
<script setup>
import { provide, ref } from 'vue'
const location = ref('North Pole')
function updateLocation() {
location.value = 'South Pole'
}
provide('location', {
location,
updateLocation
})
</script>
<!--注入方-->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location') </script>
<template>
<button @click="updateLocation">
{{ location }}
</button>
</template>