目录
新的单文件组件特性
- <script setup>
- 更少的样板内容,简洁的代码
- 可以用纯typeScript 声明props和定义自定义事件。
- 更好的运行时性能
- 更好的ide类型推断性能 减少语言服务从代码中抽离类型的工作
- <script> 只在组件被首次引入的时候仅执行一次不同
- <script setup> 中的代码会在每次组件实例被创建的时候执行。
- <script setup> 中的代码,例如初始化的赋值等在组件每次实例创建时都重新执行一次。
:is 动态组件
-
递归组件
- 如果有命名的import导入和组件的推断名冲突了可以使用import别名导入
- import { Foo as FooChild } from './components'
-
命名空间组件
- 可以使用带点的组件标记,例如<Foo.Bar>来引用嵌套在对象属性中的组件。这在需要从这个单个文件中导入多个组件的时候非常有用:
Components/index.ts 用于导出组件
- 可以使用带点的组件标记,例如<Foo.Bar>来引用嵌套在对象属性中的组件。这在需要从这个单个文件中导入多个组件的时候非常有用:
props中使用-----defineProps
运行时声明和类型声明
- 运行时声明
- 只有在运行的时候才可以检测,是否按照类型进行传递
- 类型声明
- 这里的类型声明指的是基于ts的类型检测,对props进行类型的约束,因此要使用类型声明,需要基于<script setup lang="ts">
props基本用法
为了在<script setup>中声明props,必须使用defineProps API,这是一个宏命令,不需要导入可以直接在<script setup>中使用并且只能在它中使用,有两种方法可以使用这个宏命令声明props,运行时声明和类型声明,不同方式下使用这个宏命令后props将具备不同的类型推断。
// 运行时声明:
// defineProps 运行时声明的基本用法,仅支持运行时校验
<script setup lang="ts">
const props = defineProps({
foo: String,
bar: {
type: Number,
required: true
}
})
</script>
// 接到props直接可以在模板中直接使用,这与vue.x是一致的
// 类型声明
<script setup lang="ts">
const props = defineProps<{
foo?: String,
bar: number
}>()
</script>
需要注意的点:
- 不能同事使用运行时声明和类型声明
- defineProps 只能是要么使用运行时声明,要么使用类型声明,同时使用两种声明方式会导致编译报错
- 使用类型声明时,静态分析(也就是约束的类型)会自动生成等效的运行时声明,以确保正确的运行时行为
- 类型字面量,如string, number,Boolean等
- 在同一文件中的interface或类型字面量的引用
- props的ts接口只能写在本文件中
-
<script setup lang="ts"> // 暂时不支持引入,因为setup 语法糖会将List 编译成一个变量,因此只能在文件内容 import { List } from "./type" interface List { id: number, content: string, isDone: boolean, }; const props = defineProps<{ title: string, list: List[], }>(); </script> // 现在还不支持复杂的类型和其他文件进行类型导入 // ts会自动扫描项目中的types来自动导入类型,可以将interface通过namespace的方式来实现自动导入,这样就不需要在文件中引入,直接就可以使用了 // types 文件夹下的list.ts文件 declare namespace List { export interface Basic { id: number, content: string, isDone: boolean, } } // 这样是可以支持的 const props = defineProps<{ title: string, list: List.Basic[], }>();
-
运行时声明和类型声明的比较
- 运行时声明
- 优势
- 不使用ts的情况下能够对props进行一定的,运行时的类型校验
- 劣势
- 运行时校验
- 只能进行基本类型的校验
- 编码时无任何提示
- 优势
- 类型声明
- 优势
- 完美的支持类型校验,包括props的完美类型约束,父组件在传props时的提示以及子组件在使用props的提示
- 劣势
- 目前ts的接口只能写在文件内,目前可通过ts自动扫描types来解决
- 优势
- 运行时声明
强烈推荐使用类型声明的defineProps
props的默认值------widthDefaults
defineProps 使用类型声明时的不足之处在于他没有可以给props提供默认值的方式。为了解决这个问题提供了widthDefaults宏命令。
基本用法:
<script setup lang='ts'>
const props = widthDefaults(defineProps <{
title?: string,
list?: List.Basic[],
}>(), {
title: 'Hello widthDefaults',
list: ()=>[{id: 3, content: '3',isDone: false}]
})
</script>
widthDefaults 辅助函数提供了对默认值的类型检查,并确保返回的props的类型删除了已经声明默认值的属性的可选标志。
注意点:
widthDefaults是为了给defineProps使用类型声明时提供添加默认值的方法, 这仅仅适用于<script setup lang='ts'>且defineProps使用类型声明。
自定义事件-----defineEmits
在<script setup>中声明emit 必须使用defineEmits API,这也是一个宏命令. 同样可采用运行时声明和类型声明式,在类型声明下emit将具备完美的类型推断。
运行时声明:
<script setup lang='ts'>
const emit defineEmits(['handleClick', 'handleChange']);
const handleClick = () => emit('handleClick', Date.now()+'');
const handleChange = () => emit('handleChange', Date.now());
</script>
类型声明式:
<script setup lang='ts'>
interface Click {
id: string,
value: number,
}
// 完美的类型检查
// List.Basic 是基于ts 自动扫描 types 文件夹以及delcare namespace 自动导入的
const emit = defineEmits<{
(e: 'handleClickWithTypeDeclaration', data: Click): void,
(e: 'handleChangeWithTypeDeclaration', data: List.Basic): void
}>();
const handleClickWithTypeDeclaration = () => emit('handleClickWithTypeDeclaration, { id: '1', val: Date.now()});
const handleChangeWithTypeDeclaration = ()=> emit('handleChangeWithTypeDeclaration', {
id: 1,
content: 'change',
isDone: false
})
</script>
跟 defineProps 一样,运行时声明和类型声明式同样不可同时使用,且类型声明只能用于在 ts 环境下。
显示的暴露----defineExpose
- <script setup>组件默认是关闭的,通过模板ref或$parent链获取的组件实例,并不会暴露任何在<script setup>中声明绑定的(变量,函数)
- 为了<script setup>组件中明确要暴露出去的属性,需要使用defineExpose 这个宏命令
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>