VUE3.3 新特性

Vue3.3 新特性总结

  • 支持类型导入(defineProps / defineEmits)
  • 泛型(defineProps / defineComponent )
  • defineProps 的解构
  • defienSlots
  • defineEmits
  • defineModel
  • defineOptions
  • toRef & toValue

一、支持类型导入

更新前,defineProps和defineEmits 只支持本地类型并且仅支持类型字面量和interface,不支持类型导入。
更新后,支持导入类型(import)、条件类型且可扩展类型(不支持复杂的条件类型)

1.defineProps 类型导入:
export interface HiProps {
	msg: string;
}
// 导入类型定义文件
	import type { HiProps } from './typings'; 
// defineProps 使用导入类型 + 条件类型 + 扩展类型 extends
	defineProps<HIProps & true extends false ? { age: number} : {}>()

二、泛型

definePropsdefineComponent 可通过generic属性接收泛型参数

1.defineProps 示例:
<script setup lang="ts" generic="T">
// 通过传入的类型推断出实际的类型
	defineProps<{age: T}>() 
</script>

<script setup lang="ts" generic="T, U extends string">
	defineProps<{age: T, names: U[]}>() 
</script>
2.defineComponent 示例:
import { defineComponent } from 'vue';
export default defineComponent(<T>(props: {msg: T}) => {
    return () => <div>{props.msg}</div>;
})
<template>
	<div>
		<Generic msg="Hi" />
	</div>
</template>
<script setup lang="ts">
	import Generic from './Generic.vue'
</script>

三、defineEmits

以前,defineEmits 的类型参数仅支持调用签名语法:

const emit = defineEmits<{
  (e: 'foo', id: number): void
  (e: 'bar', name: string, ...rest: any[]): void
}>()

现在,在类型字面量中,key 是事件名称,value 是事件参数的数组类型

	const emit = defineEmits<{
        foo: [id: number];
        bar: [name: string, age: number];
	}>();
	function handleEmitFoo(){
        emit('foo', 1);
	}

四、defineSlots

defineSlots() 只接受一个类型参数(类型字面量)
在类型字面量中,key 是slot 的名称,value 是slot 的函数

<template>
	<div>
		<slot msg="test"></slot>
		<slot name="foo" :bar="1"></slot>
	</div>
</template>
<script setup lang="ts">
  defineSlots<{
      default: (props: { msg: string }) => any;
      foo: (props: { bar: number }) => any;
  }>();
</script>
<template>
	<div>
		<Sloter>
			<template v-slot="{msg}">{{ msg}}</template>
			<template v-slot:foo="{bar}">{{ bar}}</template>
		</Sloter>
	</div>
</template>
<script setup lang="ts">
	import Sloter from './Sloter.vue';
</script>

五、defineProps的解构

可以解构的 props 并保持响应性

1.首先需要在vite.config.ts 中开启配置:
export default {
  plugins: [
    vue({
      propsDestructure: true;
    })
  ]
}
2.使用示例:
<script setup lang="ts">
	const { msg } = defineProps<HiProps>(); // HiProps类型定义在其他文件中
	watchEffect(() => {
        console.log(msg);
        // msg是一个普通的值,编译完是props.msg,watchEffect可以收集到
	})
	function useTest(msg){
        // msg是一个普通的值,响应式会丢失
	}
</script>
<template>
	<div>
		<Hi :msg="msg">
		<el-button @click="handleMsg">change msg</el-button>
	</div>
</template>
<script setup lang="ts">
	import Hi from './Hi.vue'
	const msg = ref('hei');
	function handleMsg(){
        msg.value += 'hi'
	}
</script>

六、defineModel

以前,数据的双向绑定需要两个步骤:

  • 声明props
  • 使用emit事件

现在,直接使用defineModel接收就可以完成数据的双向绑定,会返回一个ref

1.首先需要在vite.config.ts 中开启配置:
export default {
  plugins: [
    vue({
      defineModel: true;
    })
  ]
}
2.使用示例:
<template>
	<div>
		<input v-model="modelValue" />
		<input v-model="bar" />
	</div>
</template>
<script setup lang="ts">
	const modelValue = defineModel()
	const bar = defineModel('bar', {
        required: false,
        default: 'test'
	})
</script>
<template>
	<div>
		<DefineModel v-model="foo" v-model:bar="bar" />
	</div>
</template>
<script setup lang="ts">
	import DefineModel from './DefineModel.vue'
	
	const foo = ref('123')
	const bar = ref('test')
</script>

七、defineOptions

defineOptions允许直接在<script setup> 中声明组件选项,而无需单独添加的<script>

<script setup>
	defineOptions({ inheritAttrs: false })
</script>

八、toRef 和 toValue

都提供了对getter的支持

1.toRef

增强toRef

  • value => ref
    toRef(1); // 相当于 ref(1)
  • getter => ref
    toRef(() => props.msg); // 创建只读ref,使用.value时执行getter
  • ref => ref
    toRef(msg.value);
<script setup lang="ts">
	const props = defineProps(['msg]);
	function useTest(msg){
      // 此处msg是一个普通的值,响应式会丢失
	}
	useTest(toRef(props, "msg")) ; // 使用toRef将msg 转换成ref, 解决响应式丢失问题
</script>
<script setup lang="ts">
	const props = defineProps<{foo: { bar: string }}>();
	function useTest(msg){
	}
	useTest(toRef(props.foo, "bar"));
</script>

问题:若直接修改了foo,则响应式会丢失
解决方法

  • 传入函数
    useTest(() => props.foo.bar);
  • 使用computed 计算属性
    useTest(computed(() => props.foo.bar)) // 有缓存开销
  • 使用toRef(增加,支持传入getter)
    useTest(toRef(() => props.foo.bar))
2.toValue
  • ref => value
    const value1 = toValue(ref(1));
  • value => value
    const value2 = toValue(2);
  • getter => value
    const value3 = toValue(() => 3);
3.toValue 和 unref 的区别

const value3 = toValue(() => 3); // 返回的是值
const unrefValue = unref(() => 2); // 返回的是函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值