当前位置:首页 >焦点 >代号:Rurouni Kenshin,vue3.3正式发布,快来尝鲜!!! 如果您正在使用 TSX 与 Vue

代号:Rurouni Kenshin,vue3.3正式发布,快来尝鲜!!! 如果您正在使用 TSX 与 Vue

2024-07-01 12:30:03 [百科] 来源:避面尹邢网

代号:Rurouni Kenshin,代号vue3.3正式发布,布快快来尝鲜!尝鲜!代号!布快

作者:一川 开发 前端 为了向后兼容,尝鲜3.3 仍然全局注册 JSX 命名空间。代号我们计划在 3.4 中删除默认的布快全局注册。如果您正在使用 TSX 与 Vue,尝鲜请在升级到 3.3后在 tsconfig.json 中添加显式的代号 jsxImportSource,以避免在 3.4 中出现问题。布快

1写在前面

Vue官方团队在5月10日宣布发布 Vue 3.3 "浪客剑心"!尝鲜

此版本专注于改进开发人员体验 ,代号特别是布快 SFC <script setup> 与 TypeScript 的使用。一同发布的尝鲜还有 1.6 版本的 Vue Language Tools (以前称为 Volar),我们解决了很多 Vue 与 TypeScript 使用上的痛点。

代号:Rurouni Kenshin,vue3.3正式发布,快来尝鲜!!! 如果您正在使用 TSX 与  Vue

想要体验Vue3.3的前提是:升级Vue到最新版本,同时升级对应的依赖项,对于一些实验性功能需要进行手动开启。

代号:Rurouni Kenshin,vue3.3正式发布,快来尝鲜!!! 如果您正在使用 TSX 与  Vue

依赖更新

代号:Rurouni Kenshin,vue3.3正式发布,快来尝鲜!!! 如果您正在使用 TSX 与  Vue

升级到 3.3 时,建议同时更新以下依赖项:

volar / vue-tsc@^1.6.4

vite@^4.3.5

@vitejs/plugin-vue@^4.2.0

vue-loader@^17.1.0(如果使用 webpack 或 vue-cli)

更多更新日志可以查看:https://github.com/vuejs/core/blob/main/CHANGELOG.md#330-2023-05-08

2defineProps和defineEmits支持外部import类型和复杂类型

在vue3.3之前的vue文件中, defineProps和defineEmits仅支持使用当前文件定义的类型,不能通过import导入外部定义的类型,且仅支持类型字面量和当前文件的interface。

在vue3.3对这一限制进行了优化,编译器可以通过AST支持解析外部impoort的类型,并支持有限的复杂类型。

<script lang='ts' setup>import type {  TestProps } from "./props";// vue3.3 支持外部导入props类型,通过泛型定义props上的属性类型defineProps<TestProps>();defineProps<TestProps & {  age: number }>();</script>

注意:defineProps和defineEmits并不是100%全面支持复杂类型,例如不能对整个props对象像普通类型一样进行条件类型,但是可以对单个prop类型使用条件类型。

import type {  TestProps } from "./props";defineProps<TestProps extends Object ? TestProps : { }>();

如上面使用条件类型,将会抛出异常:

图片

详细说明见:PR#8083

3通过generic属性定义泛型组件

使用vue的setup语法糖的组件,可以通过在generic属性传递泛型类型参数,从而构成泛型组件:

<script lang='ts' setup generic="T, U">defineProps<{   options: T[],  selected: T,  id: U}>()</script>

通过generic接受的泛型类型,和Typescript中的泛型的参数列表使用方法是一样的,这就意味着你可以定义多个泛型参数、使用extends约束、默认类型和引用import导入的类型。

<script lang='ts' setup generic="T extends Option, U">import {  Option } from "./props"defineProps<{   options: T[],  selected: T,  id: U}>()</script>

注意:此功能在之前需要显式开启,在最新版本的volar/vue-tsc中已支持默认开启。

详细说明见:RFCS#436

4更符合人体工程学的 defineEmits

在Vue3.3之前的defineEmits的类型仅支持使用签名语法:

interface EmitsType<T, U>{   (event: 'change', value: T): void  (event: 'click', value: T, ...rest:U[]): void}defineEmits<EmitsType<string, any>>()
interface EmitsType<T, U>{   change: (value: T) => void  click: (value: T, ...rest:U[]) => void}defineEmits<EmitsType<string, any>>()

此种方式定义的类型和emit返回的类型匹配,但是在实际开发中编写代码比较冗长和笨拙,Vue3.3对此进行优化使得更加符合人类习惯。

interface EmitsType<T, U>{   change: [ value: T ],  click: [ value:T, ...rest: U[] ]}defineEmits<EmitsType<string,any>>()

在使用类型字面量形式中,键key是事件名称,值value是指定附加参数的数组类型,对此可以使用标识元组元素的形式。见元组元素标记

Vue3.3对于defineEmits的泛型定义形式并不是破坏性改变,对原有的签名语法依旧支持。

5使用 defineSlots 设置 slots 类型

Vue3.3后的defineSlots宏支持声明预期的插槽和对应插槽的props类型。

<template>  <div>    <slot title="default" />    <slot name="header" title="header"></slot>  </div></template><script lang='ts' setup>interface SlotsType{   default?: (props: {     title: string  })=>any;  header?: (props: {     title: string  })=>any}defineSlots<SlotsType>()</script>

当前,defineSlots仅接受一个类型参数,不支持运行时参数,且类型参数限制为一个类型字面量:

  • key:slot名称
  • value:slot函数,插槽函数的第一个参数是插槽期望接受的props,其定义的类型是用于模板中的插槽props。

defineSlots 的返回值与 useSlots 返回的插槽对象相同。

注意:

  • volar / vue-tsc 尚未实现 slots 类型检查。
  • slot 函数的返回类型目前是忽略的,是any类型,但我们可能会在将来利用它进行 slot 内容检查。

此外,defineComponent 用法也有对应的 slots 选项。 这两个 API 都没有运行时影响,并且纯粹用作 IDE 和 vue-tsc 的类型提示。

import {  SlotsType } from 'vue'defineComponent({   slots: Object as SlotsType<{     default: {  foo: string; bar: number }    item: {  data: number }  }>,  setup(props, {  slots }) {     expectType<undefined | ((scope: {  foo: string; bar: number }) => any)>(      slots.default    )    expectType<undefined | ((scope: {  data: number }) => any)>(slots.item)  }})

更多详情见:PR#7982

6实验性功能

响应式props解构

响应式props解构此前是现已删除的 Reactivity Transform 的一部分,Vue3.3现已将其拆分成独立功能。

响应式props解构的功能毫无疑问是为解构后的props属性提供响应式,此外还提供了更加符合用户习惯的声明props默认值方式。

<template>  <div>    my friend‘s name is: { {  name }}  </div></template><script lang='ts' setup>import {   watchEffect } from "vue"// 官方给出的demo是这样写,但是我发现不能对props进行泛型类型声明,解构后的属性失去了类型推断 不建议使用这种方式const {   name ="dudu" } = defineProps(["name"])// 个人推荐搭配withDefaults进行赋默认值和响应式解构,有解构需要时可以进行解构赋值,没有时可以在withDefaults中赋默认值const {   name = "dudu" } = withDefaults(defineProps<{ }>(),{ })watchEffect(()=>{    // 在 watchers 和 computed getters 中访问 `name`   // 将其作为依赖项进行跟踪,就像访问 `name` 一样  console.log(`my friend‘s name is: ${ name}`)})</script>

官方给出的demo是这样写,但是实际使用中发现不能对props进行泛型类型声明,解构后的属性失去了类型推断 不建议使用这种方式。

const {   name ="dudu" } = defineProps(["name"])

个人推荐搭配withDefaults进行赋默认值和响应式解构,有解构需要时可以进行解构赋值,没有时可以在withDefaults中赋默认值。

const {   name = "dudu" } = withDefaults(defineProps<{ }>(),{ })

如果搭配withDefaults同时进行响应式解构时赋默认值,那么解构时不能改变withDefaults赋的默认值,也就是withDefaults的默认值是不可改变的。

const {   name ="dudu" } = withDefaults(defineProps<{   name: string}>(),{   name:"dudududududu"})

我们看到只会显示withDefaults的默认值:

图片

注意:此功能是实验性功能,需要在打包配置中进行手动开启。

更多详情见:RFC#502

defineModel

在Vue3.3前的组件想要支持v-model使用,需要:

  • 声明props
  • 在打算更新props时,使用emit进行相应的update:proName事件

子组件支持v-model的方式:

<template>   <input :value="modelValue" @input="onInput" /></template><script lang='ts' setup>// BEFORE: Vue3.3前的方式const props = defineProps(['modelValue'])const emit = defineEmits(['update:modelValue'])console.log(props.modelValue)function onInput(e) {   emit('update:modelValue', e.target.value)}</script>

与此同时,父组件需要进行对应声明使用:

<script setup lang="ts">import DefineModel from './components/DefineModel.vue';const name = ref("dudu")</script><template>  <DefineModel v-model:modelValue="name"/></template>

执行效果:

图片

Vue3.3引入了一个名为 defineModel 的新 SFC 宏,该宏增强了声明 v-model 使用的双向绑定道具时的开发人员体验。使用 defineModel ,v-model绑定的props 可以像 ref 一样被声明和解构。

  • defineModel 宏是 <script setup> 的专用功能。
  • 编译时,它将声明一个同名的 prop 和一个相应的 update:propName 事件。
  • 默认情况下处于禁用状态,需要手动开启。

defineModel简化了声明props和emit的过程,会自动注册一个prop,并返回一个可以直接改变的 ref:

<template>  <div>输入的名字:{ { modelValue}}</div>  <input v-model="modelValue"  /></template><script lang='ts' setup>// AFTER: Vue3.3后的方式const modelValue =  defineModel()console.log(modelValue.value)</script>

根据接受 defineModel 返回值的变量名,这里是 modelValue,会自动定义 props 名为 modelValue,emit 事件为 update:modelValue。

此外,defineModel也支持声明变量名称、类型和赋初值,其实就是props和emit的结合体。

const count = defineModel<number>('count', {  default: 0 })

注意:Vue3.3引入了一个新的编译器脚本选项 defineModel ,默认情况下处于禁用状态,需要手动进行配置开启。

在vite的配置如下:

// https://vitejs.dev/config/export default defineConfig({   plugins: [vue({     // propsDestructure: true,    script: {       defineModel: true,    }  })],})

更多详情见:RFC#503

7其他特性

新增宏defineOptions

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

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

增强 toRef 和 toValue 实现更好的 getter 支持

toRef 已得到增强以支持将值/getters/现有 refs 规范化为 refs:

// 相当于 ref(1)toRef(1)// 创建只读 ref,使用 .value 时执行 gettertoRef(() => props.foo)// 返回 reftoRef(existingRef)

使用 getter 调用 toRef 类似于 computed,但是当 getter 只执行属性访问而没有昂贵的计算时,可以更高效。

新的 toValue 工具方法提供相反的功能,即将值/ getter / ref 规范化为值:

toValue(1) //       --> 1toValue(ref(1)) //  --> 1toValue(() => 1) // --> 1

toValue 可以在组合式函数中代替 unref,以便组合式函数可以接受 getter 作为响应式数据源:

// 以前:分配不必要的中间引用useFeature(computed(() => props.foo))useFeature(toRef(props, 'foo'))// 现在:更高效和简洁useFeature(() => props.foo)

toRef 和 toValue 之间的关系类似于 ref 和 unref 之间的关系,主要区别在于 getter 函数的特殊处理。

JSX 导入源支持

目前,Vue 的类型自动注册全局 JSX 类型。这可能会与需要 JSX 类型推断的其他库一起使用时发生冲突,特别是 React。

从3.3开始,Vue 支持通过 TypeScript 的 jsxImportSource 选项指定 JSX 命名空间。这允许用户根据其需要,选择全局或每个文件的选择加入。

为了向后兼容,3.3 仍然全局注册 JSX 命名空间。我们计划在 3.4 中删除默认的全局注册。如果您正在使用 TSX 与  Vue,请在升级到 3.3后在 tsconfig.json 中添加显式的 jsxImportSource,以避免在 3.4 中出现问题。

按计划,Vue官方的目标是在2023年开始制作较小,更频繁的功能发行版。

更多内容阅读:vue官方博客https://blog.vuejs.org/posts/vue-3-3

8写在最后

Vue3.3没有进行大的功能破坏性改变,在使用体验上更加符合人体工程学和用户习惯,没有心智负担。

Vue3.3主要有以下变化:

  • 增强defineProps和defineEmits支持外部import类型和复杂类型
  • 新增通过generic属性定义泛型组件
  • 增强更符合人体工程学的 defineEmits
  • 增强使用 defineSlots 设置 slots 类型

实验性功能:

  • 响应式props解构
  • 新增defineModel实现v-model属性更新值

其他特性:

  • 新增宏defineOptions声明组件选项
  • 增强 toRef 和 toValue 实现更好的 getter 支持
  • JSX 导入源支持

学而知不足,水平有限,还望诸君多多指教。觉得文章不错的读者,不妨点个关注,收藏起来上班摸鱼的时候品尝。

责任编辑:武晓燕 来源: 宇宙一码平川 兼容JSXVue

(责任编辑:知识)

    推荐文章
    • 圆满交付!中远海运完成空客第600架次飞机部件全程物流运输

      圆满交付!中远海运完成空客第600架次飞机部件全程物流运输4月25日,由中远海运提供全程物流运输服务的空客亚洲总装线项目第600架次A320飞机大部件,历经欧洲段驳运、海运、天津段全封闭陆路运输,顺利运抵空客公司位于天津港保税区的空客总装厂并圆满交付。空客亚 ...[详细]
    • 网络直播遭遇瓶颈 电商直播打破壁垒反成热门

      网络直播遭遇瓶颈 电商直播打破壁垒反成热门随着互联网视频市场日益火爆,内容创业者和平台服务商不断融入,再加上“围观”群众的热情,互联网视频服务近年来流量激增。那么,这些流量如何能够转变为生意上的收入,为内容创业者和平台服务商提供进一步发展的动 ...[详细]
    • 网友调侃小米新LOGO被骗 雷军回应亮了

      网友调侃小米新LOGO被骗 雷军回应亮了在小米春季新品发布会上,小米公司宣布启用新LOGO,由日本国际著名设计师原研哉操刀设计,提出全新的设计理念,为小米品牌视觉融入东方哲学的思考。新LOGO公布后引发网友热议,表示看起来只是从方形变成了椭 ...[详细]
    • 你会买吗?库克谈苹果造车:将探索无人驾驶

      你会买吗?库克谈苹果造车:将探索无人驾驶最近数码圈热点莫过于小米进军电动汽车行业,雷军亲自带队,并表示这将是自己人生中最后一次重大创业。一直以来,新能源汽车和手机厂商一直有着相当微妙的关系,不止小米,此前还有着华为、苹果造车的传闻,电动汽车 ...[详细]
    • 人寿保险有哪些险种 中国人寿保险怎么样?

      人寿保险有哪些险种 中国人寿保险怎么样?人寿保险有哪些险种?人寿保险的险种包括定期人寿保险,终身人寿保险,生存保险,生死两全保险,养老保险(由生存保险和死亡保险结合而成,是生死两全保险的特殊表现形式)等。此外,因为巨大灾难也成为了威胁人身安 ...[详细]
    • 《死亡细胞》恶魔城DLC发布实机游玩视频

      《死亡细胞》恶魔城DLC发布实机游玩视频去年的TGA上,《死亡细胞》宣布与《恶魔城》联动,将带来该游戏上市以来体量最大的DLC。今天1月20日),游戏开发商公开了该DLC的实际游戏画面,我们可以看到大量来自恶魔城系列的元素。《死亡细胞》重返 ...[详细]
    • 1080亿现金打底 电动汽车将会是雷军人生最后一次创业项目

      1080亿现金打底 电动汽车将会是雷军人生最后一次创业项目在今天下午小米公司正式发布了将要进军智能电动汽车领域的公告之后,晚间的小米春季新品发布会上,雷军也对这个事件进行了一些相关的解说。雷军表示:造车话题,这些年来,在小米高管会上偶尔讨论过几次。但是直到今 ...[详细]
    • 艾瑞资本合伙人范明:投资,另一种企业管理咨询

      艾瑞资本合伙人范明:投资,另一种企业管理咨询创投名片范明艾瑞资本 合伙人上海交通大学MBA,实战派资深企业管理咨询专家,拥有十几年企业管理和咨询经验,2015年7月加盟艾瑞集团,担任艾瑞集团副总裁、企业CEO教练双重职位。负责集团人事及行政管理 ...[详细]
    • 农行掌上银行怎么关闭小额免密支付 具体步骤是什么?

      农行掌上银行怎么关闭小额免密支付 具体步骤是什么?农行银行卡默认开通小额免密免签支付功能,虽然平时消费方便,但也存在安全隐患,那么在农行掌上银行上要怎么关闭小额免密支付功能呢?农行掌上银行怎么关闭小额免密支付?【1】首先在手机上打开并登录农业银行Ap ...[详细]
    • 智能共享充电宝公司“小电”完成千万天使轮融资

      智能共享充电宝公司“小电”完成千万天使轮融资据悉,智能共享充电宝公司“小电”宣布获得数千万元天使轮融资,本轮融资由盈动资本、金沙江创投、王刚、德同资本、招银国际联合投资。此轮融资后,小电将大规模铺设,今年计划全国铺360万台智能充电宝。小电科技 ...[详细]
    热点阅读