banner
banner
banner
NEWS LETTER

VUE3-组件知识

Scroll down
  • 组件名格式:PascalCase

组件注册

  • 全局注册
  • 局部注册

全局注册 — 只有多个页面都要用到才使用全局

1
2
3
import { createApp } from 'vue'
const app = create({})
app.component('注册的名字', 写好的组件) --可以被链式调用

局部注册

  • 使用该组件的父组件引入且在components:{}中注册

Props声明 — 组件间通信父传子

  • Prop名字的格式:camelCase

用法

  • 子组件:在props定义好属性,然后使用
  • 父组件:在组件中调用这个属性,传值

组件的props标注类型 — ts

  • defineComponent(): 启用类型推导
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import { defineComponent } from 'vue'

    export default defineComponent({
    props: {
    name: String,
    age: Number
    },
    mounted() {
    this.name // 类型: string | undefined
    }
    })
  • PropType: 多层级时启用工具类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import { defineComponent } from 'vue'
    import type { PropType } from 'vue'

    interface Book {
    title: string
    author: string
    year: number
    }

    export default defineComponent({
    props: {
    book: {
    type: Object as PropType<Book>,
    required: true
    },
    callback: Function as PropType<(id: number) => void >
    // validater 和 default ts版本低于4.7要使用箭头函数
    },
    mounted() {
    this.book.title // string
    this.callback?.('123')
    }
    })

静态prop:

1
prop="只能传字符串"

动态prop:

1
:prop="可传多种类型"

使用一个对象绑定多个prop:

1
v-bind="对象数据"

单向数据流

单向数据流

  • 所有props都遵循着单向绑定原则
  • props因父组件的更新而变化
  • ❌ 子组件更改prop

prop校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
props:{
propA: {
type: 该属性的类型
default: 该属性的默认值
required: true 该属性必传
},
propB: [类型A, 类型B] // 多类型
propC: {
type: Object | Function
default(){}
},
propC: {
validator(value){} // 自定义类型校验函数
}
}

组件事件

触发与监听事件

  • 子组件事件

    • 子组件上的要监听事件要调用 $emit 方法,通过传入事件名称来抛出一个事件
    • 示例:
      1
      <button @click="$emit('enlarge-text')">文本</button>
  • 父组件事件

    • 通过 v-on 或 @ 来选择性监听子组件上的事件
    • 示例:
      1
      <子组件名 @enlarge-text="表达式" />

事件参数

  • 子组件:$emit(事件名,事件参数)
  • 父组件:
    1
    2
    3
    @事件名="(事件参数) => 表达式" 
    或者
    @事件名="事件处理函数", 然后在methods写事件处理函数

显式声明触发事件+标注类型 emits + ts

  • 语法:
    1
    2
    emits:[] // 字符串数组语法
    emits:{} //对象语法,支持校验
  • 示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // addBook为事件名,
    // bookName为事件内的一个属性且类型为字符串
    emits:{
    addBook(payload:{bookName: string}) {
    return payload.bookNAme.length > 0
    }
    },
    methods: {
    onSubmit: {
    this.$emit('addBook',{
    bookName: '5655'
    })
    }
    }

组件 v-model

  • 默认情况下,v-model 在组件上都是使用 modelValue 作为 prop,并以 update:modelValue 作为对应的事件

组件上使用v-model实现双向绑定

  • 方法一
    • 组件内的表单元素要有以下两行
      1
      2
      :value="modelValue"
      @input="$emit('update:modelValue'),$event.target.value"
  • 方法二
    • 使用具有 getter 和 setter 的 computed 属性
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      <script>
      export default {
      props: ['modelValue'],
      emits: ['update:modelValue'],
      computed: {
      value: {
      get() {
      return this.modelValue
      },
      set(value) {
      this.$emit('update:modelValue', value)
      }
      }
      }
      }
      </script>

      <template>
      <input v-model="value" />
      </template>

v-model的参数 — 适用于组件有多个 v-model 绑定

  • 通过给 v-model 指定一个参数来更改modelValue这个名
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 名字从modelValue改为title
    父组件: <子组件名 v-model:title="" />
    子组件:
    <script>
    export default {
    props: ['title'],
    emits: ['update:title']
    }
    </script>

    <template>
    <input
    type="text"
    :value="title"
    @input="$emit('update:title', $event.target.value)"
    />
    </template>

处理 v-model 修饰符

  • 自定义的修饰符 capitalize
  • 示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    父组件: <MyComponent v-model.capitalize="myText" />
    子组件:
    <script>
    export default {
    props: {
    modelValue: String,
    modelModifiers: {
    default: () => ({}) // 默认触发事件
    }
    },
    emits: ['update:modelValue'],
    methods: {
    // 写给修饰符的对应事件
    emitValue(e) {
    let value = e.target.value
    if(this.modelModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
    }
    this.$emit('update:modelValue',value)
    }
    }
    }
    </script>

    <template>
    <input
    type="text"
    :value="modelValue"
    @input="emitValue"
    />
    </template>

透传 Attributes:传递给一个组件,却没有被组件声明的属性或v-on

1
<组件名 class="btn"></组件名> // 这个组件的根元素就多了一个btn的类

单根节点:有自动 attribute 透传行为

  • 禁用Attributes继承:inheritAttrs: false
  • 使用 v-bind=”$attrs” 可以让透传的attribute指定到目标元素

多根节点(一个组件多个子组件):没有自动 attribute 透传行为

  • 必须使用 v-bind=”$attrs” 让透传的attribute指定到目标元素

插槽slot —在组件中添加 slot标签

  • 插槽的内容无法访问到子组件的状态
  • v-slot 简写 #
  • 具名插槽: 适用一个组件多个插槽
    1
    <slot name="" /> // 无名=默认插槽
  • 父组件
    1
    2
    3
    4
    5
    6
    <BaseLayout>
    // 当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 `<template> `节点都被隐式地视为默认插槽的内容
    // 指定插入那个插槽
    <template v-slot:插槽名></template>
    <template #插槽名></template>
    </BaseLayout>
  • 动态插槽名:
    1
    <template #[插槽名]></template>
  • 作用域插槽
    • 插槽内容想要同时使用父组件域内和子组件域内的数据
    • 传递prop:
      1
      <slot name="可不写为默认插槽" message="hello" />
    • 接受插槽:
      • 默认插槽:
        1
        <组件名 v-slot="slotProps">{{slotProps.xxx}}</组件名>
      • 具名插槽:
        1
        <组件名 #插槽名="插槽名Props">{{}}</组件名>

依赖注入

Provide

  • 为组件后代提供数据
    1
    2
    3
    4
    5
    exeport default {
    provide: {
    message: 'test'
    }
    }

应用层 Provide

  • 为整个应用层提供依赖app页面
    1
    app.provide('注入名',值)

Inject

  • 注入上层组件提供的数据
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    export default {
    inject: ['message'],
    created() {
    console.log(this.message) // test
    }
    data() {
    return {
    fullMessage: this.meaaage // data的时候拿得到this.message
    }
    }
    }

注入别名/默认值(不要求必须有提供者)

1
2
3
4
5
6
inject: {
别名: {
from: '原注入名', // 别名
default: 'default value' // 默认值,无提供者时
},
}

和响应式数据配合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { computed } from 'vue'

export default {
data() {
return {
message: 'hello!'
}
},
provide() {
return {
// 显式提供一个计算属性
message: computed(() => this.message)
}
}
}

异步组件

  • 仅在需要时再从服务器加载相关组件 defineAsyncComponent
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    import { defineAsyncComponent } from 'vue'

    // 方法一:
    const AsyncComp1 = defineAsyncComponent(() => {
    return new Promise((resolve, reject) => {
    // ...从服务器获取组件
    resolve(/* 获取到的组件 */)
    })
    })

    // 方法二:
    const AsyncComp2 = defineAsyncComponent({
    loader: () => import('组件路径'), // 加载组件
    loadingComponent: LoadingComponent, // 加载异步组件时使用的组件
    delay: 200, // 展示加载组件前的延迟时间,默认为 200ms
    errorComponent: ErrorComponent, // 加载失败后展示的组件
    timeout: 3000
    })

    // ... 像使用其他一般组件一样使用 `AsyncComp`

    // 全局注册:
    app.component('MyComponent', defineAsyncComponent(() =>
    import('./components/MyComponent.vue')
    ))

    // 局部注册:
    components: {
    异步组件名: defineAsyncComponent(() =>
    import('./components/MyComponent.vue')
    )
    }

动态组件 — 适用于Tab界面

  • 在多个组件间作切换时,被切换掉的组件会被卸载
    1
    <component :is="组件名/组件对象">

DOM 模板 — 在 DOM 中直接书写 Vue 模板

  • 区分大小写,以 kebab-case (短横线连字符) 形式
  • 显示关闭标签: <></>
  • 元素位置限制,ul标签、ol标签、tr标签 等要放在特定元素中才会显示
  • 解决办法:
    1
    2
    3
    <table>
    <tr is="vue:要放的组件名" />
    </table>
其他文章
cover
Git找不到null文件
  • 24/11/01
  • 16:45
  • 前端工程化工具
目录导航 置顶
  1. 1. 组件注册
    1. 1.1. 全局注册 — 只有多个页面都要用到才使用全局
    2. 1.2. 局部注册
  2. 2. Props声明 — 组件间通信父传子
    1. 2.1. 用法
    2. 2.2. 组件的props标注类型 — ts
    3. 2.3. 静态prop:
    4. 2.4. 动态prop:
    5. 2.5. 使用一个对象绑定多个prop:
    6. 2.6. 单向数据流
    7. 2.7. prop校验
  3. 3. 组件事件
    1. 3.1. 触发与监听事件
    2. 3.2. 子组件事件
    3. 3.3. 父组件事件
    4. 3.4. 事件参数
    5. 3.5. 显式声明触发事件+标注类型 emits + ts
  4. 4. 组件 v-model
    1. 4.1. 组件上使用v-model实现双向绑定
    2. 4.2. v-model的参数 — 适用于组件有多个 v-model 绑定
    3. 4.3. 处理 v-model 修饰符
  5. 5. 透传 Attributes:传递给一个组件,却没有被组件声明的属性或v-on
    1. 5.1. 单根节点:有自动 attribute 透传行为
    2. 5.2. 多根节点(一个组件多个子组件):没有自动 attribute 透传行为
  6. 6. 插槽slot —在组件中添加 slot标签
  7. 7. 依赖注入
    1. 7.1. Provide
    2. 7.2. 应用层 Provide
    3. 7.3. Inject
    4. 7.4. 注入别名/默认值(不要求必须有提供者)
    5. 7.5. 和响应式数据配合使用
  8. 8. 异步组件
  9. 9. 动态组件 — 适用于Tab界面
  10. 10. DOM 模板 — 在 DOM 中直接书写 Vue 模板
请输入关键词进行搜索