# 深入组件 ## 组件注册 ### 全局注册 ```js import { createApp } from 'vue' const app = createApp({}) app.component( // 注册的名字 'MyComponent', // 组件的实现 { /* ... */ } ) // 单文件组件 import MyComponent from './App.vue' app.component('MyComponent', MyComponent) // .component() 方法可以被链式调用 app .component('ComponentA', ComponentA) .component('ComponentB', ComponentB) .component('ComponentC', ComponentC) ``` ### 命名 - PascalCase:大驼峰 ## Props ### Props 声明 - 使用 ` ``` - 没有使用 ` ``` ### 单向数据流 - 不能重新赋值props - 能修改引用类型,但是会造成损耗不推荐 ### Prop 校验 ```js defineProps({ // 基础类型检查 // (给出 `null` 和 `undefined` 值则会跳过任何类型检查) propA: Number, // 多种可能的类型 propB: [String, Number], // 必传,且为 String 类型 propC: { type: String, required: true }, // Number 类型的默认值 propD: { type: Number, default: 100 }, // 对象类型的默认值 propE: { type: Object, // 对象或数组的默认值 // 必须从一个工厂函数返回。 // 该函数接收组件所接收到的原始 prop 作为参数。 default(rawProps) { return { message: 'hello' } } }, // 自定义类型校验函数 // 在 3.4+ 中完整的 props 作为第二个参数传入 propF: { validator(value, props) { // The value must match one of these strings return ['success', 'warning', 'danger'].includes(value) } }, // 函数类型的默认值 propG: { type: Function, // 不像对象或数组的默认,这不是一个 // 工厂函数。这会是一个用来作为默认值的函数 default() { return 'Default function' } } }) ``` ## 组件事件 ```vue click me ``` ![](./vue3深入组件.assets/3d9f574cc12244ecb8dcab9ef49d7697.png) ### 事件参数 ```vue Increase by 1 count += n" /> ``` ### 声明触发的事件 - 我们在 `` 中使用的 `$emit` 方法不能在组件的 ` ``` ### 事件校验 - 要为事件添加校验,那么事件可以被赋值为一个函数,接受的参数就是抛出事件时传入 emit 的内容,返回一个布尔值来表明事件是否合法。 ```vue ``` ## 组件 v-model - `v-model` 可以在组件上使用以实现双向绑定。 ```vue ``` ### v-model 的参数 ```vue ``` ```vue ``` ### 多个 v-model 绑定 ```vue ``` ```vue ``` # ? 传递对象是否还在使用ref响应式的参数 ## 透传 Attributes ### Attributes 继承 ```vue click me click me ``` ### `class` 和 `style`合并 - `template`下只有一个元素的话会继承,多个的话就不会,见**多根节点的 Attributes 继承** ### `v-on` 监听器继承 ### 深层组件继承——重写组件的话,会被子组件调用的子组件继承 ### 禁用 Attributes 继承 ```vue ``` ### 多根节点的 Attributes 继承 - 和单根节点组件有所不同,有着多个根节点的组件没有自动 attribute 透传行为。如果 $attrs 没有被显式绑定,将会抛出一个运行时警告。 - 如果 有下面这样的多根节点模板,由于 Vue 不知道要将 attribute 透传到哪里,所以会抛出一个警告。 - 如果 $attrs 被显式绑定,则不会有警告: ```vue ... ... ``` ### 在 JavaScript 中访问透传 Attributes ```vue ``` ## 插槽 Slots ### 默认内容 ```vue Submit ``` ### 具名插槽 - `v-slot` 有对应的简写 `#`,因此 `` 可以简写为 ``。其意思就是“将这部分模板片段传入子组件的 `header` 插槽中”。 ```vue Here might be a page title A paragraph for the main content. And another one. Here's some contact info ``` ### 动态插槽名 ```vue ... ... ``` ### 作用域插槽——使用自组建的传值 ```vue {{ slotProps.text }} {{ slotProps.count }} {{ text }} {{ count }} ``` ### 具名作用域插槽 ```vue {{ headerProps }} {{ defaultProps }} {{ footerProps }} ``` ## 依赖注入 - 解决多级props传递 ### Provide (提供) ```vue ``` ### 应用层 Provide ```js import { createApp } from 'vue' const app = createApp({}) app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!') ``` ### Inject (注入) ```vue ``` ### 使用 Symbol 作注入名 - 包含非常多的依赖提供,很麻烦 ```js // keys.js export const myInjectionKey = Symbol() ``` ## 异步组件 ? 懒加载? ### 基本用法 ```js import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent(() => { return new Promise((resolve, reject) => { // ...从服务器获取组件 resolve(/* 获取到的组件 */) }) }) // ... 像使用其他一般组件一样使用 `AsyncComp` ``` ### ES 模块动态导入也会返回一个 Promise ```js import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent(() => import('./components/MyComponent.vue') ) app.component('MyComponent', defineAsyncComponent(() => import('./components/MyComponent.vue') )) ``` ```vue ``` ### 加载与错误状态 ```js const AsyncComp = defineAsyncComponent({ // 加载函数 loader: () => import('./Foo.vue'), // 加载异步组件时使用的组件 loadingComponent: LoadingComponent, // 展示加载组件前的延迟时间,默认为 200ms delay: 200, // 加载失败后展示的组件 errorComponent: ErrorComponent, // 如果提供了一个 timeout 时间限制,并超时了 // 也会显示这里配置的报错组件,默认值是:Infinity timeout: 3000 }) ```
A paragraph for the main content.
And another one.
Here's some contact info