Vue学习笔记 - 深入组件 - 注册,透传Attribute,异步组件

学完互动教程,已经有个基本印象,再看看文档,基础部分有涉及了,所以看深入组件那部分文档

注册

全局注册

可以使用 Vue 应用实例的 .component() 方法,让组件在当前 Vue 应用中全局可用

js 复制代码
import { createApp } from 'vue'

const app = createApp({})

app.component(
  // 注册的名字
  'MyComponent',
  // 组件的实现
  {
    /* ... */
  }
)

如果使用单文件组件,你可以注册被导入的 .vue 文件:

js 复制代码
import MyComponent from './App.vue'

app.component('MyComponent', MyComponent)

.component() 方法可以被链式调用:

全局注册的组件可以在此应用的任意组件的模板中使用

局部注册

全局注册的问题

  1. 打包的时候,没有用到的组件也不会被移除(tree-shaking)
  2. 全局注册在大型项目中使项目的依赖关系变得不那么明确

局部注册的组件需要在使用它的父组件中显式导入,并且只能在该父组件中使用。它的优点是使组件之间的依赖关系更加明确,并且对 tree-shaking 更加友好

js 复制代码
<script>
import ComponentA from './ComponentA.vue'

export default {
  components: {
    ComponentA
  }
}
</script>

<template>
  <ComponentA />
</template>

昨天学的互动教程里的写法就是局部注册的方式

组件名格式

使用 PascalCase 作为组件名的注册格式

PascalCase 就是大驼峰的命名

  1. PascalCase 是合法的 JavaScript 标识符。这使得在 JavaScript 中导入和注册组件都很容易,同时 IDE 也能提供较好的自动补全。
  2. <PascalCase /> 在模板中更明显地表明了这是一个 Vue 组件,而不是原生 HTML 元素。同时也能够将 Vue 组件和自定义元素 (web components) 区分开来

这两点确实有道理

透传 Attributes

Attributes 继承

"透传 attribute"指的是传递给一个组件,却没有被该组件声明为 propsemitsattribute 或者 v-on 事件监听器。最常见的例子就是 classstyleid

当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素

表述有点书面化,但是看完例子后非常容易理解

js 复制代码
<!-- 比如 <MyButton> 的模板是下面这样的 -->
<button>Click Me</button>

<!-- 父组件中使用MyButton组件 -->
<MyButton class="large" />

<!-- 最终渲染的结果: 父组件中声明的class属性透传到MyButton组件了 -->
<button class="large">Click Me</button>

<!-- 如果原来MyButton组件里已经有class属性,最后结果相当于把父组件里的属性再追加上去 -->
<button class="btn">Click Me</button>

<button class="btn large">Click Me</button>

这里有个问题,如果是id怎么办,也是直接加上去?

打开创建的前几天创建的VueDemo工程

sh 复制代码
# 报权限错误可以加sudo
npm run dev

App.vueHelloworld.vue的父组件,而且Helloworld.vue 满足单个元素作为根渲染

App.vue 添加id属性

js 复制代码
...
<HelloWorld msg="You did it!" id="new_attr_id" />

...
<style scoped>
<!-- 如果结果是父组件,则是蓝色 -->
#new_attr_id {
    color: blue;
}
#attr_id {
    color: green;
}
...

Helloworld.vue

js 复制代码
...
<div class="greetings" id="attr_id">
...

最终结果显示了父组件

去掉父组件里的id,则显示子组件的id

小结:

  1. Attribute 透传: 子组件根节点加样式,一般适用于class,id,style。其中class是追加的,而id是使用父组件替换掉子组件

依赖注入

应用层 Provide

js 复制代码
import { createApp } from 'vue'

const app = createApp({})

app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')

Prop 逐级透传问题

通常情况下,当我们需要从父组件向子组件传递数据时,会使用 props。想象一下这样的结构:有一些多层级嵌套的组件,形成了一棵巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦:

注意,虽然这里的 <Footer> 组件可能根本不关心这些 props,但为了使 <DeepChild> 能访问到它们,仍然需要定义并向下传递。如果组件链路非常长,可能会影响到更多这条路上的组件。这一问题被称为"prop 逐级透传",显然是我们希望尽量避免的情况。

provideinject 可以帮助我们解决这一问题

示例图已经比较清楚说明了ProviderInject的用途了

完整示例

App.vue

js 复制代码
<script>
import Child from './Child.vue'

export default {
  components: { Child },
  provide() {
    return {
      message: '传给孙子组件'
    }
  }
}
</script>

<template>
  <Child />
</template>

Child.vue

js 复制代码
<script>
import GrandChild from './GrandChild.vue'

export default {
  <!-- 局部注册子组件 -->
  components: {
    GrandChild
  }
}
</script>

<template>
  <GrandChild />
</template>

GrandChild.vue

js 复制代码
<script>
export default {
  <!-- 声明使用父组件传下来的message -->
  inject: ['message']
}
</script>

<template>
  <p>
    Message to grand child: {{ message }}
  </p>
</template>

异步组件

基本用法

在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了 defineAsyncComponent 方法来实现此功能:

js 复制代码
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...从服务器获取组件
    resolve(/* 获取到的组件 */)
  })
})
// ... 像使用其他一般组件一样使用 `AsyncComp`

导入单文件组件

js 复制代码
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
)

最后得到的 AsyncComp 是一个外层包装过的组件,仅在页面需要它渲染时才会调用加载内部实际组件的函数。它会将接收到的 props 和插槽传给内部组件,所以你可以使用这个异步的包装组件无缝地替换原始组件,同时实现延迟加载。

加载与错误状态

js 复制代码
const AsyncComp = defineAsyncComponent({
  // 加载函数
  loader: () => import('./Foo.vue'),

  // 加载异步组件时使用的组件
  loadingComponent: LoadingComponent,
  // 展示加载组件前的延迟时间,默认为 200ms
  delay: 200,

  // 加载失败后展示的组件
  errorComponent: ErrorComponent,
  // 如果提供了一个 timeout 时间限制,并超时了
  // 也会显示这里配置的报错组件,默认值是:Infinity
  timeout: 3000
})

最后的感想

Vue的文档很清晰,导致这部分大多数是"转译"下原来的文档,价值寥寥,只能算熟悉框架了.....

耐心点,慢慢来

参考

相关推荐
Hilaku20 分钟前
那个把代码写得亲妈都不认的同事,最后被劝退了🤷‍♂️
前端·javascript·代码规范
南囝coding20 分钟前
Node.js 原生功能狂飙,15 个热门 npm 包要失业了
前端·后端
Dragon Wu22 分钟前
TanStack Query(React Query) 常用api及操作总结
前端·javascript·前端框架
火柴就是我24 分钟前
canvas.rotate(rotation); 到底是往哪个方向转动
前端
光影少年31 分钟前
前端算法新手如何刷算法?
前端·算法
梦想是准点下班1 小时前
【vue3】 + 【vite】 + 【vite-plugin-obfuscator】混淆打包 => 放弃了,样式会丢
前端·vue.js
前端达人1 小时前
原生JavaScript vs 前端框架,2026年该怎么选?
开发语言·前端·javascript·前端框架·ecmascript
漫天黄叶远飞1 小时前
React 组件通讯全攻略:拒绝 "Props" 焦虑,掌握数据流动的艺术
前端·react.js·前端框架
梦想是准点下班1 小时前
【vue3】 + 【vite】 + 【rollup-plugin-obfuscator】混淆打包 => 打包报错
前端·vue.js
恋猫de小郭1 小时前
Flutter UI 设计库解耦重构进度,官方解答未来如何适配
android·前端·flutter