Vue3.0最新进展:script-setup定稿,部分实验性API将被弃用script-setup的新特性在小版本中有了很大的改变,之前的用法也做了很多调整。距离上一篇讨论script-setup的新特性(回顾上一篇文章[1])已经过去4个多月了,虽然截至7月2日的3.1.4版本,script-setup还处于实验阶段,但就在同一天,友达在推特上发布推文[2],宣布将在3.2.0版本中脱离实验状态,正式进入Vue3.0团队。我们简单回顾一下这次草案所做的一些调整:之前弃用了useContextAPI,可以通过这个API获取组件的上下文信息,包括父子组件通信数据和attrs、slots、emit、emit、并曝光。//导入useContext组件import{useContext}from"vue";//获取contextconstctx=useContext();这个API在3.2版本之后会被删除,context中的数据会被新的useSlots和useAttrsAPI替代。新增useSlotsAPI和useAttrsAPIuseContextAPI被删除后,原来的context数据将通过这两个新的API获取。useAttrs顾名思义,useAttrs可以用来获取attrs数据(即非props属性值)。//导入useAttrs组件import{useAttrs}from"vue";//获取attrsconstattrs=useAttrs();//attrs是一个对象,和props一样,需要获取对应的单个attrconsole.log(attrs.msg);如果一个属性在当前组件中没有被指定为props,那么父组件绑定的属性值将被输入到attrs中,并通过这个新的API获取。useSlots同样,通过API的命名,也可以理解为是用来获取slot数据的。但是这个API对于大部分同学来说应该较少使用,因为大部分Vue开发者应该使用的是SFC模式(单组件),插槽可以直接在模板中使用标签渲染。因此,我个人认为这个API的目标用户是JSX/TSX的开发者。简单使用参考如下:父组件,可传入默认槽和命名槽:IamadefaultslotfromTSX。
IamamsgslotfromTSX.
然后在JSX/TSX子组件中,使用useSlots来获取父组件传入的槽数据进行渲染:import{defineComponent,useSlots}from"vue";constChildTSX=defineComponent({setup(){//获取槽数据constslots=useSlots();//渲染组件return()=>(
//渲染默认插槽
{slots.default?slots.default():""}
//渲染命名插槽
{slots.msg?slots.msg():""}
);},});exportdefaultChildTSX;添加defineExposeAPI在标准组件写法中,子组件的数据默认是隐式暴露给父组件的,但是在script-setup模式下,所有数据默认只返回给模板,不会对外暴露组件,因此父组件不能通过r直接挂载如果ef变量获取的是子组件的数据,如果要调用子组件的数据,需要暴露在子组件的显示器上,才能正确获取。这个操作是通过expose来完成的。Expose也是context的一个组件成员。原来的用法来源于useContext://导入useContext组件import{useContext}from"vue";//启用expose组件const{expose}=useContext();//定义一个我要提供父级获取的数据componentconstmsg:string="HelloWorld!";//在父组件获取expose({msg,})之前显示暴露的数据;由于useContext在以后的版本中会被移除,所以增加了defineExposeAPI来实现expose的功能。新API用法://导入defineExpose组件import{defineExpose}from"vue";//定义数据constmsg:string="HelloWorld!";//暴露给父组件defineExpose({msg,});父组件可以使用refAPI获取子组件暴露的msg数据。重命名defineEmitsAPI使用defineEmits替换原来的defineEmitAPI,即重命名。嗯,我之前的文章也特别强调过defineProps是以s结尾的复数,而defineEmit不是。现在,它们都是统一的,而且都是复数形式。从友达的更新说明来看,很可能只是错别字更新。与原来的defineEmit相比,目的是使用新的defineEmits在命名上更接近标准组件的emits,与defineProps更统一。╮(╯▽╰)╭所以在用法上和原来没有区别://导入defineEmits组件import{defineEmits}from"vue";//获取emitconstemit=defineEmits(["say-hi","chang-name"]);//调用emit打招呼emit("say-hi","Hello!");//调用emit重命名emit("chang-name","Tom");添加withDefaultsAPI发射完成后,往往与同时出现的道具也有一些变化。这次带来了一个新的withDefaultsAPI来辅助defineProps指定props的默认值。正如我在之前的文章中提到的,当你使用TypeScript编程时,defineProps有两种规范方法:1.通过构造函数检查(传统方法)第一种方法是使用JavaScript原生构造函数进行类型规范,使用这种方法时,如果你想要限制props的类型和默认值,需要给defineProps传递一个“object”入参,例如://ImportdefinePropscomponentimport{defineProps}from"vue";//DefinepropsdefineProps({name:{类型:字符串,必需:假,默认:“Petter”,},用户信息:对象,标签:数组,});1.使用类型注解来检查(TSspecific)第二种方式是遵循TS这种情况下,需要遵循TypeScript的类型规范,比如string是string,不是String。//导入defineProps组件import{defineProps}from"vue";//对象类型接口interfaceUserInfo{id:number;age:number;}//定义propsdefineProps<{name:string;phoneNumber:number;userInfo:UserInfo;tags:string[];}>();import{defineProps,withDefaults}from"vue";withDefaults(defineProps<{size?:number;labels?:string[];}>(),{size:3,labels:()=>["defaultlabel"],});import{defineProps,withDefaults}from"vue";withDefaults(defineProps<{size?:number;labels?:string[];}>(),{size:3,标签:()=>["默认标签"],});在此之前,使用第二种方式,是无法指定默认值的(当时RFC文档中也写明了不能指定)。现在,新的withDefaultsAPI允许您在使用TS类型系统时为props指定默认值。它接收两个输入参数:可能缺少一些官方说明,或者看参考用法可能更直观:import{defineProps,withDefaults}from"vue";withDefaults(defineProps<{size?:number;labels?:string[];}>(),{size:3,labels:()=>["defaultlabel"],});顶层的await支持可以不用async直接使用。在这种情况下,组件的设置将自动更改为异步设置。转换成标准组件:参考资料以上所有资料均来自友达在PR227的评论通知....com[3]非常隐秘,原来RFC仓库里的文档也被删除了,找了好久才找到新的。本文先根据游达公告打一波简单说明,文章首发于博客,仅同步知乎。Vue3.0的最新进展:script-setup已经完成,一些实验性API将被弃用。