编辑
2023-04-06
VUE3
0
请注意,本文编写于 595 天前,最后修改于 588 天前,其中某些信息可能已经过时。

目录

单文件组件和动态组件
单文件组件
说明
EG
单文件组件的优点
属性方法无需手动返回
自动注册子组件
动态组件
EG
父子组件传值
父组件传值给子组件
说明
注意点
EG
props
说明
运行时声明
说明
EG
基于类的声明
说明
EG
设置默认值
解构写法
子组件触发自定义事件
emits
说明
注意点
单文件组件中使用
组件注册
全局注册
说明
特点
EG
局部注册
说明
全局注册和局部注册的差别

单文件组件和动态组件

单文件组件

说明

.vue结尾的文件中script标签包含setup属性称之为单文件组件

EG

vue
<template></template> <script setup></script> <style></style>

单文件组件的优点

属性方法无需手动返回

常规setup函数中需要将定义的属性或方法返回,但是单文件组件则不需要

vue
<template> <h1>单文件组件</h1> <h4 @click="oldmen">{{name}} is {{age}}</h4> </template> <script setup> import { ref } from "@vue/reactivity"; const name = ref('xm') const age = ref(24) const oldmen = ()=> { age.value++ } </script> <style></style>

自动注册子组件

在单文件组件内,只需要import引入子组件后就可以直接在<template></template>中使用

vue
<template> <h1>单文件组件</h1> <h4 @click="oldmen">{{name}} is {{age}}</h4> <ComponentsTestsVue></ComponentsTestsVue> </template> <script setup> import { ref } from "@vue/reactivity"; import ComponentsTestsVue from "./ComponentsTests.vue"; const name = ref('xm') const age = ref(24) const oldmen = ()=> { age.value++ } </script> <style></style>

动态组件

使用:is动态绑定被注册的组件名或导入的组件对象 一般建议使用shallowRef或者markRaw对组件的Proxy代理取消掉,节省性能

使用:is在多个组件间切换,被切换掉的组件会被卸载,可以通过<keepalive></keepalive>组件使得被卸载的组件任然保持活跃状态

EG

vue
<template> <h1>单文件组件</h1> <button v-for="item in comlist" :key="item.name" @click="changeCom(item.id)">{{item.name}}</button> <component :is="currentTab.name"></component> </template> <script setup> import { reactive, markRaw } from "vue"; import ComponentsTestsVue from "./ComponentsTests.vue"; import ComponentsTests2Vue from "./ComponentsTests2.vue"; import ComponentsTests3Vue from "./ComponentsTests3.vue"; const comlist = reactive([ {'id':1,'name':'test1组件'}, {'id':2,'name':'test2组件'}, {'id':3,'name':'test3组件'}, ]) let currentTab = reactive({'name': markRaw(ComponentsTestsVue)}) const changeCom = (v) =>{ switch (v) { case 1 : currentTab.name = markRaw(ComponentsTestsVue) break; case 2 : currentTab.name = markRaw(ComponentsTests2Vue) break; case 3 : currentTab.name = markRaw(ComponentsTests3Vue) break; default : currentTab.name = markRaw(ComponentsTestsVue) break; } } </script> <style></style>

父子组件传值

父组件传值给子组件

说明

  1. 子组件中通过defineProps规定要接受的参数,可以搭配withDefaults设置默认值
  2. 父组件可以通过v-bind传值

注意点

  • 所以的props都应该符合单向数据流原则,即不允许子组件修改父组件传递过来的值
  • 对于props传递的值为数组或对象类型,子组件内无法更改,但是可以更改数组或对象内部的值(因为数组和对象都是引用数据类型)所以应当避免此类情况

EG

vue
<script lang='ts' setup> const LoadPageProps = { title: '页面正在加载', subTitle: '请稍等~' } </script> <template> <LoadPage :title="LoadPageProps.title" :subTitle="LoadPageProps.subTitle"/> <!-- 等价与 --> <LoadPage v-bind="LoadPageProps"/> </template> <style scope></style>

props

说明

对于props有两种声明方式

  • 运行时声明
    • 可以设置默认值
  • 基于类的声明
    • 需要借用编辑器宏withDefaults实现默认值

运行时声明

说明

传入defineProps()的参数会作为运行时的props选项使用

EG
ts
<script setup lang="ts"> const props = defineProps({ foo: { type: String, required: true }, bar: Number }) props.foo // string props.bar // number | undefined </script>

基于类的声明

说明

指的是在使用defineProps()是使用泛型函数形式 泛型参数必须为:

  • 类型字面量
  • 对同一个文件中的接口或对象类型字面量的引用

注意点 接口或对象字面类型可以包含从其他文件导入的类型引用,但是泛型参数本身不能是一个导入的类型 对于.vue文件是单独编译的,并不会抓取分析源类型,所以暂时不支持

EG

<script setup lang="ts"> const props = defineProps<{foo:string,Bar?:Number}>() props.foo // string props.Bar // number | undefined // 配合接口使用 interface props_interface { foo: string, Bar?: number } const props = defineProps<props_interface>() props.foo // string props.Bar // number | undefined </script>

设置默认值

通过编辑器宏withDefaults实现

ts
<script setup lang="ts"> // 配合接口使用 interface props_interface { foo: string, Bars?: number } const props = withDefaults(defineProps<props_interface>(),{ foo: 'hello world', Bars: 13 }) props.foo // string props.Bars // number </script>

解构写法

需要更改vite.config.ts配置

// 插件配置 plugins: [ vue({ reactivityTransform: true }) ],
ts
<script setup lang="ts"> // 对 defineProps() 的响应性解构 // 默认值会被编译为等价的运行时选项 const { name, count = 100 } = defineProps<Props>() </script>

子组件触发自定义事件

emits

说明

用于组件的emits标注类型

注意点

defineEmits必须在setup的顶级作用域下,不能在子函数中

单文件组件中使用

ts
<script setup lang="ts"> // 对emits标注类型 // 运行时声明 const emit = defineEmits(['change', 'update']) function changeChildren() { emit('change',) } // 基于类型 const emit = defineEmits<{ (e: 'change', id: number): void (e: 'update', value: string): void }>() function changeChildren() { emit('change') // const emit: (e: "change", id: number) => void (+1 overload) } </script>

defineEmits

组件注册

全局注册

说明

即在main.ts中注册

特点

  • 全局注册的组件可以在任意组件中使用

EG

ts
import MyComponent from './App.vue' app.component('MyComponent', MyComponent) // app.component(MyComponent)

局部注册

说明

在单文件组件中引入的子组件会自动注册,无需手动注册

vue
<script setup> import NoData from './NoData.vue' </script> <template> <NoData /> </template>

全局注册和局部注册的差别

  • 全局注册的组件即使没有使用到,但是在打包时并不会被自动移除,任然出现在打包后的JS文件中
  • 全局注册的组件在项目庞大时可能导致依赖关系混乱,影响项目的长期可维护性

本文作者:RKLS

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!