Vue组件

作者: 韧心222 | 来源:发表于2023-09-13 09:03 被阅读0次

组件可以将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成层层嵌套的树状结构

1 组件组成

TemplateDemo.vue

<template>
    <div class="container">
        {{ msg }}
    </div>
</template>
<script>
export default {
    data(){
        return {
            msg: 'Hello World'
        }
    }
}
</script>
<style scoped>
.container{
    font-size: 20px;
    color: blue;
}
</style>

2 组件引用

组件引用共有三个步骤:

  • 用import引入组件
  • 用注入组件
  • 显示组件
<template>
    <!-- 显示组件 -->
    <TemplateDemo />
</template>
<script>
// 引入组件
import TemplateDemo from './components/TemplateDemo.vue'
// 注册组件
export default {
    components: {
        TemplateDemo
    }
}
</script>
<style>
</style>

3 全局注册与局部注册

一个 Vue 组件在使用前需要先被“注册”,这样 Vue 才能在渲染模板时找到其对应的实现。组件注册有两种方式:全局注册和局部注册。

3.1 全局注册

可以在main.js中创建app对象后使用 app.component() 方法,让组件在当前 Vue 应用中全局可用。

import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
import TemplateDemo from './components/TemplateDemo.vue'

const app = createApp(App)
// 全局注册
app.component('TemplateDemo', TemplateDemo)

// 全局样式
app.mount('#app')

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

app
  .component('ComponentA', ComponentA)
  .component('ComponentB', ComponentB)
  .component('ComponentC', ComponentC)

局部注册

全局注册虽然很方便,但有以下几个问题:

  1. 全局注册,但并没有被使用的组件无法在生产打包时被自动移除 (也叫“tree-shaking”)。如果你全局注册了一个组件,即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中。
  2. 全局注册在大型项目中使项目的依赖关系变得不那么明确。在父组件中使用子组件时,不太容易定位子组件的实现。和使用过多的全局变量一样,这可能会影响应用长期的可维护性。

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

在使用 <script setup> 的单文件组件中,导入的组件可以直接在模板中使用,无需注册:

<script setup>
import ComponentA from './ComponentA.vue'
</script>

<template>
  <ComponentA />
</template>

如果没有使用 <script setup>,则需要使用 components 选项来显式注册:

import ComponentA from './ComponentA.js'

export default {
  components: {
    ComponentA
  },
  setup() {
    // ...
  }
}

对于每个 components 对象里的属性,它们的 key 名就是注册的组件名,而值就是相应组件的实现,等价于:

export default {
  components: {
    ComponentA: ComponentA
  }
  // ...
}

4 组件传递数据 prop

组件与组件之间不是完全独立的,而是有交集的,那就是组件与组件之间是可以传递数据的,传递数据的解决方案就是 props

要传递给子组件传递一个数据(比如,标题),必须在组件的 props 列表上声明它,也可以使用 defineProps 宏(当在script标签中使用了setup):

<!-- 子组件.vue -->
<template>
  <h4>{{ title }}</h4>
</template>

<script setup>
defineProps(['title'])
</script>

如果没有使用 <script setup>,props 必须以 props 选项的方式声明:

export default {
  props: ['title'],
}

当一个 prop 被注册后,可以像这样以自定义 attribute 的形式传递数据给它:

<Child title="My journey with Vue" />
<Child title="Blogging with Vue" />
<Child title="Why Vue is so fun" />

props只能从父组件传递给子组件

props是只读的

4.1 动态prop

可以使用 v-bind 或缩写 : 来进行动态绑定的 props

<Child :title="title" />

4.2 适用对象绑定多个prop

如果想要将一个对象的所有属性都当作 props 传入,可以使用没有参数的 v-bind,即只使用 v-bind,例如这里有一个对象post

const post = {
  id: 1,
  title: 'My Journey with Vue'
}

以及下面的模板:

<Child v-bind="post" />

这等价于:

<Child :id="post.id" :title="post.title" />

4.3 Prop校验

要声明对 props 的校验,需要向 defineProps() 宏提供一个带有 props 校验选项的对象,也可以直接在props中提供校验对象:

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' }
    }
  },
  // 自定义类型校验函数
  propF: {
    validator(value) {
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // 函数类型的默认值
  propG: {
    type: Function,
    // 不像对象或数组的默认,这不是一个
    // 工厂函数。这会是一个用来作为默认值的函数
    default() {
      return 'Default function'
    }
  }
})

5. 组件事件

在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件 (例如:在 v-on 的处理函数中),一般用于组件之间传递数据

<!-- Child -->
<button @click="$emit('someEvent')">click me</button>

父组件可以通过 v-on (缩写为 @) 来监听事件:

<!-- Parent -->
<Child @some-event="callback" />

6. 透传Attributes

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

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

如果你不想要一个组件自动地继承 attribute,你可以在组件选项中设置 inheritAttrs: false

<script setup>
defineOptions({
  inheritAttrs: false
})
</script>

相关文章

网友评论

      本文标题:Vue组件

      本文链接:https://www.haomeiwen.com/subject/dqtpvdtx.html