【Vue3】组件
注册组件
全局注册
在应用上注册的组件是全局组件,可在应用下的所有组件上使用(多个全局组件可互相引用),无需再次注册。
import { createApp } from "vue";
import MyComponent from "./App.vue";
import MyComponent2 from "./App2.vue";
const app = createApp({});
// 注册方法可链式调用
app
.component("MyComponent", MyComponent)
.component("MyComponent2", MyComponent2);
全局注册组件的缺点:
- 不会被
tree-shaking
,打包体积变大。 - 会导致依赖关系不明确,增加维护难度。
局部注册
局部注册的组件无法在后代组件中使用。
在 <script setup>
中导入的组件可直接使用,无需注册:
<script setup>
import ComponentA from './ComponentA.vue'
</script>
<template>
<ComponentA />
</template>
选项式 API 需要显示注册组件。
根节点
Vue3
中组件可以拥有多个根节点:
- myComp.vue
<template>
t1:{{ title }}
<input type="text" />
<button @click="onBtnClick()">btn-t1</button>
</template>
单个根节点时,在组件上绑定的 class
会直接绑定到根元素上,多个根节点时,需要用组件的 $attrs
属性来指定哪个元素来接收 class
。
<script setup>
)
组件配置(props
使用 defineProps()
方法声明 props,声明的 props 可以直接在模板中使用,该方法返回一个 proxy 对象,其中包含了可以传递给组件的所有 props。
props 对象形式的完整配置和 Vue2 类似,可配置默认值和校验函数。
import { defineProps } from "vue";
// 简单字符串形式声明
const props = defineProps(["title"]);
// 对象形式声明
defineProps({
title: String,
likes: Number,
});
事件
在组件中使用 defineEmits()
方法声明可在组件上绑定的事件,该方法返回一个函数,作用与 $emit()
函数一致,可调用该方法在组件中抛出事件。
import { defineEmits } from "vue";
const emit = defineEmits(["enlarge-text"]);
function onBtnClick() {
emit("enlarge-text", 91);
}
选项式 API 可在 emits
选项中声明事件,同时可在 setup()
方法的第二个参数,即 setup 上下文对象上访问到 emit 函数:
export default {
emits: ["enlarge-text"],
setup(props, ctx) {
ctx.emit("enlarge-text");
},
};
所有未在子组件内的声明的事件都将被认为是原生事件。
slot 插槽
用 useSlots()
方法获取插槽的引用对象。
import { useSlots } from "vue";
const slots = useSlots();
透传 attribute
在组件上绑定的属性、事件如果没有在组件内定义,则会被视为透传的 attribute,当组件只有一个根元素时这些透传 attribute 会被添加到根元素上。
透传进来的属性可以在组件模板中用 $attrs
访问,同时 $attrs
也包含了除组件所声明的 props 和 emits 之外的所有其他 attribute。
可以在 <script setup>
中使用 useAttrs()
方法来访问 $attrs
:
<script setup>
import { useAttrs } from "vue";
const attrs = useAttrs();
</script>
使用选项式 Api 时可以在 setup()
方法中访问,或者用 this.$attrs
访问:
export default {
setup(props, ctx) {
// 透传 attribute 被暴露为 ctx.attrs
console.log(ctx.attrs);
},
mounted() {
console.log(this.$attrs);
},
};
单根节点下透传 attribute 会自动继承
假设 <mycomp/>
是一个单根节点组件且未声明 click
事件,下例中的 click
事件会直接绑定在 <mycomp/>
组件的根元素上。
<mycomp @click="handle" />
要禁止组件自动继承透传 attribute 需要在组件选项中设置 inheritAttrs: false
。
<script>
// 使用普通的 <script> 来声明选项
export default {
inheritAttrs: false,
};
</script>
defineExpose()
使用 <script setup>
的组件是默认关闭的,需要通过 defineExpose()
方法定义要暴露的属性,与 setup()
中的 expose()
方法一致。
使用组件
v-bind
直接用 v-bind
给组件传递一个对象可以便捷的将对象的每个属性传递给 props:
<template>
<BlogPost v-bind="post" />
<!-- 等价于 -->
<BlogPost :id="post.id" :title="post.title" />
</template>
<script setup>
const post = {
id: 1,
title: "My Journey with Vue",
};
</script>
Boolean
类型的 props 可在使用组件时只绑定属性名,会在组件中自动转换为 true
:
<template>
<!-- 等同于传入 :disabled="true" -->
<MyComponent disabled />
<!-- 等同于传入 :disabled="false" -->
<MyComponent />
</template>
<script setup>
defineProps({
disabled: Boolean,
});
</script>
v-model
异步组件
Vue3
中用 defineAsyncComponent()
方法声明异步组件。
import { defineAsyncComponent } from "vue";
// 注册异步组件
app.component(
"MyComponent",
defineAsyncComponent(() => import("./components/MyComponent.vue"))
);
defineAsyncComponent()
方法返回一个 resolve 组件对象的 Promise。
import { defineAsyncComponent } from "vue";
const AsyncComp = defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
// ...从服务器获取组件
resolve(/* 获取到的组件 */);
});
});
// ... 像使用其他一般组件一样使用 `AsyncComp`
如果要处理错误状态、加载失败后展示的组件等逻辑可以使用高级选项。