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