const emits = defineEmits<{
search: [query: string]
handleUser: [id: string]
注意:原本这种调用签名的语法写法仍然支持
3、新增宏 defineOptions
以前在禁止组件继承没被自身接受的props时,需要新增一个单独的<script>
标签
<script lang="ts">
export default {
inheritAttrs: false
<script>
<script setup lang="ts">
<script>
现在可以使用defineOptions
,无需新增一个<script>
了
<script setup lang="ts">
defineOptions<{
// 指定不继承哪些属性
name: "name1",
age: 'age1'
inheritAttrs: false
<script>
4、新增宏 defineModel
在以前,如果使用v-model
支持双向绑定组件时,通常时需要props
和emit
配合,在监听数据变化 emit
一个事件
子组件ChildrenInput
:
const props = defineProps(['modelValue']) // 接收props
const value = computed({
get() {
return props.modelValue
set(val) {
emits('update:modelValue', val) // 监听到数据变化emit变化的数据
<template>
<input v-model="value" />
</template>
const modelValue = ref('')
<template>
<ChildrenInput v-model="modelValue" />
</template>
其中,子组件在实现双向绑定上,略微繁琐,vue3.3
中就新增了一个宏:defineModel
代替子组件接收并监听props
最后emit
这一步操作
子组件ChildrenInput
:
const value = defineModel('') // defineModel宏
<template>
<input v-model="value" />
</template>
编译时,defineModel
将声明一个具有相同名称的 prop
和一个相应的 update:propName
事件
const modelValue = ref('')
<template>
<ChildrenInput v-model="modelValue" />
<h1>{{ modelValue }}</h1>
</template>
注意:defineModel
目前还是一个实用性的功能,需要手动开启
vue3.3+
@vitejs/plugin-vue@^4.2.0
、vite@^4.3.5
vue-loader@^17.1.0
(如果使用 webpack 或 vue-cli)
vite
中的配置:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue({
script: {
defineModel: true // 开启defineModel
vue-cli
:
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
.tap((options) => {
return {
...options,
defineModel: true
5、toRef
和 toValue
5.1 toRef
toRef
的作用是用于提取响应式对象的属性,将其变成ref
import { reactive, toRef } from 'vue'
const obj = reactive({
const aRef = toRef(obj, 'a')
无论通过obj.a
更改值还是aRef.value
取更改值,obj
和aRef
都可以进行响应式变化,这就是toRef
的用法
现在,toRef
支持只接受一个参数,并且会转换成一个getter
,与computed
的区别就是它没有setter
toRef(1)
toRef(() => props.foo)
toRef(ref(1))
它最终得到的是一个响应式的只读ref
const obj = reactive({
const aRef = toRef(() => obj.a)
obj.a
变化时,aRef
也会变化
减少不必要的性能开销,相比于computed
,因为它无需设置setter
,因为它是只读的
适用于需要实时获取响应式数据,又无需更改该数据的场景(代替computed
):
1.实时获取prop
:
const name = toRef(() => props.name)
2. 获取路由params
或query
const id = toRef(() => route.params.id)
总之,将对象属性转化成ref
,推荐使用最新语法toRef(() => object.key)
5.2 toValue
新增的toValue
是将value
、getter
、ref
转化成值:
toValue(1) // 1
toValue(ref(1)) // 1
toValue(() => 1) // 1
toValue
与toRef
基本是一个相反的结果,返回是一个非响应性的普通数据
源码的实现:
function unref(ref2) {
return isRef(ref2) ? ref2.value : ref2;
function toValue(source) {
return isFunction(source) ? source() : unref(source);
6、props
支持外部导入
<script setup lang="ts">
import type { Props } from './foo'
// imported + intersection type
defineProps<Props & { extraProp?: string }>()
</script>
7、通用组件
<script setup lang="ts" generic="T">
defineProps<{
items: T[]
selected: T
</script>
<Conponment1 :items="[1, 2, 3]" :selected="1">
<Conponment1 :items="[true, false]" :selected="true">
还可以使用多个类型、约束等
参考文献:
https://blog.vuejs.org/posts/vue-3-3
https://github.com/vuejs/core/pull/7997
https://advanced-inertia.com/blog/vue-3-3