当前位置:   article > 正文

vue3-深入组件-组件注册和props更多细节_vue3中怎么在setup中注册组件

vue3中怎么在setup中注册组件

组件注册

定义好的组件需要注册才能被使用。 注册方式有两种

  1. 全局注册

  2. 局部注册

全局注册

.component() 方法,让组件在当前 Vue 应用中全局可用。 在 main.ts 中

  1. import './assets/main.css'
  2. import { createApp } from 'vue'
  3. import { createPinia } from 'pinia'
  4. import GlobalTitle from '@/components/GlobalTitle.vue'
  5. import App from './App.vue'
  6. import router from './router'
  7. const app = createApp(App)
  8. app.component('GlobalTitle'GlobalTitle)
  9. app.use(createPinia())
  10. app.use(router)
  11. app.mount('#app')

在 vue 中直接使用无需导入

  1. <script lang="ts" setup>
  2. import { ref } from 'vue'
  3. </script>
  4. <template>
  5.   <div class="container">
  6.     <GlobalTitle></GlobalTitle>
  7.   </div>
  8. </template>
  9. <style lang="scss" scoped>
  10. .container {
  11. }
  12. </style>

效果:

全局注册的组件可以在此应用的任意组件的模板中使用,所有的子组件也可以使用全局注册的组件。

全局组件缺点

  • 全局注册,但并没有被使用的组件无法在生产打包时被自动移除 (也叫“tree-shaking”)。如果你全局注册了一个组件,即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中。

  • 全局注册在大型项目中使项目的依赖关系变得不那么明确。在父组件中使用子组件时,不太容易定位子组件的实现。和使用过多的全局变量一样,这可能会影响应用长期的可维护性。

局部注册

局部注册的组件需要在使用它的父组件中显式导入,并且只能在该父组件中使用。

它的优点是使组件之间的依赖关系更加明确,并且对 tree-shaking 更加友好。

定义组件

  1. <script lang="ts" setup>
  2. import { ref } from 'vue'
  3. </script>
  4. <template>
  5.   <div class="container">
  6.     <h2>这是一个局部组件</h2>
  7.   </div>
  8. </template>
  9. <style lang="scss" scoped>
  10. .container {
  11. }
  12. </style>

局部使用组件

  1. <script lang="ts" setup>
  2. import { ref } from 'vue'
  3. import PartTitle from '@/components/PartTitle.vue'
  4. </script>
  5. <template>
  6.   <div class="container">
  7.     <PartTitle />
  8.   </div>
  9. </template>
  10. <style lang="scss" scoped>
  11. .container {
  12. }
  13. </style>

组件名格式

推荐 PascalCase 作为组件名的注册格式。

  1. PascalCase 是合法的 JavaScript 标识符。这使得在 JavaScript 中导入和注册组件都很容易,同时 IDE 也能提供较好的自动补全。

  2. <PascalCase /> 在模板中更明显地表明了这是一个 Vue 组件,而不是原生 HTML 元素。同时也能够将 Vue 组件和自定义元素 (web components) 区分开来。

在单文件组件和内联字符串模板中,我们都推荐这样做。

为了方便,Vue 支持将模板中使用 kebab-case 的标签解析为使用 PascalCase 注册的组件。

这意味着一个以 MyComponent 为名注册的组件,在模板中可以通过 <MyComponent> 或 <my-component> 引用。这让我们能够使用同样的 JavaScript 组件注册代码来配合不同来源的模板。

props

Props 声明

一个组件需要显式声明它所接受的 props,这样 Vue 才能知道外部传入的哪些是 props,哪些是透传 attribute。

setup 写法

组件定义

  1. <script lang="ts" setup>
  2. import { ref } from 'vue'
  3. const props = defineProps(['person'])
  4. </script>
  5. <template>
  6.   <div class="container">
  7.     <h1>{{ props.person }}</h1>
  8.   </div>
  9. </template>
  10. <style lang="scss" scoped>
  11. .container {
  12. }
  13. </style>

组件使用

  1. <script lang="ts" setup>
  2. import { ref } from 'vue'
  3. import Com14 from '@/components/Com14.vue'
  4. </script>
  5. <template>
  6.   <div class="container">
  7.     <Com14 person="'王大可'" />
  8.   </div>
  9. </template>
  10. <style lang="scss" scoped>
  11. .container {
  12. }
  13. </style>

声明对象形式的属性 setup JavaScript 形式

  1. defineProps({
  2.   title: String,
  3.   likes: Number
  4. })

setup TypeScript 形式

  1. <script setup lang="ts">
  2. defineProps<{
  3.   title?: string
  4.   likes?: number
  5. }>()
  6. </script>

对象形式的 props 声明不仅可以一定程度上作为组件的文档,而且如果其他开发者在使用你的组件时传递了错误的类型,也会在浏览器控制台中抛出警告。

传递 prop 的细节

Prop 属性命名

如果一个 prop 的名字很长,应使用 camelCase 形式,因为它们是合法的 JavaScript 标识符

  1. defineProps({
  2.   greetingMessage: String
  3. })
  4. <span>{{ greetingMessage }}</span>
  5. //推荐写法
  6. <MyComponent greeting-message="hello" />
  7. //或者
  8. <MyComponent greetingMessage="hello" />

模版上使用属性则通常会将其写为 kebab-case 形式,这样和 HTML attribute 写法就一致了。

静态 vs. 动态 Prop

简单讲 就是传入数值是字符串还是变量

  1. //这是静态
  2. <Com14 person="王大可" />
  3. //这是动态
  4. <Com14 :person="personName" />
使用一个对象绑定多个 prop

v-bind 直接绑定对象,即只使用 v-bind 而非某一个属性

  1. const post = {
  2. id: 1,
  3. title: 'My Journey with Vue'
  4. }
  5. <BlogPost v-bind="post" />
  6. // 实际等价于
  7. <BlogPost :id="post.id" :title="post.title" />
单向数据流
  1. 所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。

  2. 这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。

  3. 每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告:

  1. const props = defineProps(['foo'])
  2. // ❌ 警告!prop 是只读的!
  3. props.foo = 'bar'

「更改 props 的场景:」

prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性。

在这种情况下,最好是新定义一个局部数据属性,从 props 上获取初始值即可

  1. const props = defineProps(['initialCounter'])
  2. // 计数器只是将 props.initialCounter 作为初始值
  3. // 像下面这样做就使 prop 和后续更新无关了
  4. const counter = ref(props.initialCounter)

需要对传入的 prop 值做进一步的转换。

在这种情况中,最好是基于该 prop 值定义一个计算属性:

  1. const props = defineProps(['size'])
  2. // 该 prop 变更时计算属性也会自动更新
  3. const normalizedSize = computed(() => props.size.trim().toLowerCase())
Prop 校验
  1. Vue 组件可以更细致地声明对传入的 props 的校验要求。

  2. 比如我们上面已经看到过的类型声明,如果传入的值不满足类型要求,Vue 会在浏览器控制台中抛出警告来提醒使用者。

  1. defineProps({
  2.   // 基础类型检查
  3.   // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  4.   propA: Number,
  5.   // 多种可能的类型
  6.   propB: [StringNumber],
  7.   // 必传,且为 String 类型
  8.   propC: {
  9.     typeString,
  10.     required: true
  11.   },
  12.   // Number 类型的默认值
  13.   propD: {
  14.     typeNumber,
  15.     default100
  16.   },
  17.   // 对象类型的默认值
  18.   propE: {
  19.     typeObject,
  20.     // 对象或数组的默认值
  21.     // 必须从一个工厂函数返回。
  22.     // 该函数接收组件所接收到的原始 prop 作为参数。
  23.     default(rawProps) {
  24.       return { message: 'hello' }
  25.     }
  26.   },
  27.   // 自定义类型校验函数
  28.   // 在 3.4+ 中完整的 props 作为第二个参数传入
  29.   propF: {
  30.     validator(value, props) {
  31.       // The value must match one of these strings
  32.       return ['success''warning''danger'].includes(value)
  33.     }
  34.   },
  35.   // 函数类型的默认值
  36.   propG: {
  37.     typeFunction,
  38.     // 不像对象或数组的默认,这不是一个
  39.     // 工厂函数。这会是一个用来作为默认值的函数
  40.     default() {
  41.       return 'Default function'
  42.     }
  43.   }
  44. })

defineProps() 宏中的参数不可以访问 <script setup> 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中。

额外说明:

  • 所有 prop 默认都是可选的,除非声明了 required: true

  • 除 Boolean 外的未传递的可选 prop 将会有一个默认值 undefined。

  • Boolean 类型的未传递 prop 将被转换为 false。这可以通过为它设置 default 来更改——例如:设置为 default: undefined 将与非布尔类型的 prop 的行为保持一致。

  • 如果声明了 default 值,那么在 prop 的值被解析为 undefined 时,无论 prop 是未被传递还是显式指明的 undefined,都会改为 default 值。

当 prop 的校验失败后,Vue 会抛出一个控制台警告 (在开发模式下)。

运行时类型检查

校验选项中的 type 可以是下列这些原生构造函数:

  • String

  • Number

  • Boolean

  • Array

  • Object

  • Date

  • Function

  • Symbol

type 也可以是自定义的类或构造函数,Vue 将会通过 instanceof 来检查类型是否匹配。

  1. class Person {
  2.   constructor(firstName, lastName) {
  3.     this.firstName = firstName
  4.     this.lastName = lastName
  5.   }
  6. }
  7. defineProps({
  8.   author: Person
  9. })

Vue 会通过 instanceof Person 来校验 author prop 的值是否是 Person 类的一个实例。

Boolean 类型转换
  1. 组件属性使用 Boolean 类型

  1. defineProps({
  2.   disabled: Boolean
  3. })
  4. <!-- 等同于传入 :disabled="true" -->
  5. <MyComponent disabled />
  6. <!-- 等同于传入 :disabled="false" -->
  7. <MyComponent />
  1. prop 被声明为允许多种类型时

只有当 Boolean 出现在 String 之前时,Boolean 转换规则才适用

  1. // disabled 将被转换为 true
  2. defineProps({
  3.   disabled: [BooleanNumber]
  4. })
  5. // disabled 将被转换为 true
  6. defineProps({
  7.   disabled: [BooleanString]
  8. })
  9. // disabled 将被转换为 true
  10. defineProps({
  11.   disabled: [NumberBoolean]
  12. })
  13. // disabled 将被解析为空字符串 (disabled="")
  14. defineProps({
  15.   disabled: [StringBoolean]
  16. })
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/215417
推荐阅读
相关标签
  

闽ICP备14008679号