百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Vue3实战笔记(33)—组件传值props终章

bigegpt 2024-08-05 11:49 8 浏览

前言

在 Vue 3 中,组件的声明方式主要有两种:运行时声明和基于类型的声明。这两种方式在 Vue 3 的 Composition API 中体现得尤为明显。


一、运行时声明、基于类型的声明

这两天一直有一个疑问,为什么这种方式声明属性不能支持Type和interface?


  //这种方式会报错,同理,Type声明的类型也不能
    defineProps({
      navigationItem :NavigationItem,//“NavigationItem”仅表示类型,但在此处却作为值使用。ts(2693)
      author: Person,
      book:shtype//“shtype”仅表示类型,但在此处却作为值使用。ts(2693
    })

先来了解一下两个概念:运行时声明、基于类型的声明

当使用


<script setup lang="ts">
const props = defineProps({
  foo: { type: String, required: true },
  bar: Number
})

props.foo // string
props.bar // number | undefined
</script>

这被称之为“运行时声明”,因为传递给 defineProps() 的参数会作为运行时的 props 选项使用。

然而,通过泛型参数来定义 props 的类型通常更直接:


<script setup lang="ts">
const props = defineProps<{
  foo: string
  bar?: number
}>()
</script>

这被称之为“基于类型的声明”。编译器会尽可能地尝试根据类型参数推导出等价的运行时选项。在这种场景下,我们第二个例子中编译出的运行时选项和第一个是完全一致的。

基于类型的声明或者运行时声明可以择一使用,但是不能同时使用。

我们也可以将 props 的类型移入一个单独的接口中:


<script setup lang="ts">
interface Props {
  foo: string
  bar?: number
}

const props = defineProps<Props>()
</script>

还可以从外部导入接口声明:


<script setup lang="ts">
import type { Props } from './foo'

const props = defineProps<Props>()
</script>

在 3.2 及以下版本中,defineProps() 的泛型类型参数仅限于类型文字或对本地接口的引用。

这个限制在 3.3 中得到了解决。最新版本的 Vue 支持在类型参数位置引用导入和有限的复杂类型。但是,由于类型到运行时转换仍然基于 AST,一些需要实际类型分析的复杂类型,例如条件类型,还未支持。您可以使用条件类型来指定单个 prop 的类型,但不能用于整个 props 对象的类型。
上一篇文章中注意到Prop校验的话,有一个默认值选项,官方文档说,

当使用基于类型的声明时,我们失去了为 props 声明默认值的能力。这可以通过 withDefaults 编译器宏解决:


export interface Props {
  msg?: string
  labels?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two']
})

这将被编译为等效的运行时 props default 选项。此外,withDefaults 帮助程序为默认值提供类型检查,并确保返回的 props 类型删除了已声明默认值的属性的可选标志。

二、一个小小的好奇心

能不能在接口中声明默认值?搜了一下:



特别好奇,尝试了一下:

interface NavigationItem{
      children: Array<NavigationItem>,
        id:string,
        name:string = 'sh',
        propDef: {
          type: String,
          required: false,
          default:""
        },
        path:string,
        child:{
          id:string,
          name:string,
          path:string,
          child:{}
        }
    }



接口中也不应该这样的写法,但是编译器没有报错:


        propDef: {
          type: String,
          required: false,
          default:""
        }

实例化时候:


这是类型啊!!!所以不要把接口和对象的各种约束等方式混淆了。老老实实按照官方文档来吧,好奇害死猫,浪费了不少时间去验证一些奇奇怪怪的想法。还有就是搜到的不一定是你需要的。

三、非script setup场景下

如果没有使用script setup,那么为了开启 props 的类型推导,必须使用 defineComponent()。传入 setup() 的 props 对象类型是从 props 选项中推导而来。


import { defineComponent } from 'vue'

export default defineComponent({
  props: {
    message: String
  },
  setup(props) {
    props.message // <-- 类型:string
  }
})

重点来了,基于类型的声明能干的事儿,运行时声明也能干
通过基于类型的声明,一个 prop 可以像使用其他任何类型一样使用一个复杂类型:


<script setup lang="ts">
interface Book {
  title: string
  author: string
  year: number
}

const props = defineProps<{
  book: Book
}>()
</script>

对于运行时声明,我们可以使用 PropType 工具类型:


import type { PropType } from 'vue'

const props = defineProps({
  book: Object as PropType<Book>
})

其工作方式与直接指定 props 选项基本相同:


import { defineComponent } from 'vue'
import type { PropType } from 'vue'

export default defineComponent({
  props: {
    book: Object as PropType<Book>
  }
})

总结

运行时声明: 这是一种传统的 Vue 组件声明方式,它主要依赖于 Vue 的运行时特性。在 Vue 2.x 中,这种方式主要通过 options API 实现,例如 data、methods、computed、watch 等。在 Vue 3 中,虽然 Composition API 被引入,但运行时声明仍然是一种可选的方式。例如,可以直接在 setup 函数中定义响应式变量、方法等,无需额外的类型注解,Vue 3 的响应式系统会在运行时自动处理这些声明。
基于类型的声明: 这种方式是 Vue 3 新引入的,特别是与 TypeScript 一起使用时,可以提供更严格的类型检查和更好的开发体验。基于类型的声明通常涉及到使用 TypeScript 的类型注解来定义组件的 props、emits、slots 以及其他响应式状态。Vue 3 的 Composition API,如 ref、reactive、computed、watch 等函数,都可以与 TypeScript 的类型系统很好地配合工作。

人间的事往往如此,当时提起痛不欲生,几年之后,也不过是一场回忆而已。

相关推荐

Go语言泛型-泛型约束与实践(go1.7泛型)

来源:械说在Go语言中,Go泛型-泛型约束与实践部分主要探讨如何定义和使用泛型约束(Constraints),以及如何在实际开发中利用泛型进行更灵活的编程。以下是详细内容:一、什么是泛型约束?**泛型...

golang总结(golang实战教程)

基础部分Go语言有哪些优势?1简单易学:语法简洁,减少了代码的冗余。高效并发:内置强大的goroutine和channel,使并发编程更加高效且易于管理。内存管理:拥有自动垃圾回收机制,减少内...

Go 官宣:新版 Protobuf API(go pro版本)

原文作者:JoeTsai,DamienNeil和HerbieOng原文链接:https://blog.golang.org/a-new-go-api-for-protocol-buffer...

Golang开发的一些注意事项(一)(golang入门项目)

1.channel关闭后读的问题当channel关闭之后再去读取它,虽然不会引发panic,但会直接得到零值,而且ok的值为false。packagemainimport"...

golang 托盘菜单应用及打开系统默认浏览器

之前看到一个应用,用go语言编写,说是某某程序的windows图形化客户端,体验一下发现只是一个托盘,然后托盘菜单的控制面板功能直接打开本地浏览器访问程序启动的webserver网页完成gui相关功...

golang标准库每日一库之 io/ioutil

一、核心函数概览函数作用描述替代方案(Go1.16+)ioutil.ReadFile(filename)一次性读取整个文件内容(返回[]byte)os.ReadFileioutil.WriteFi...

文件类型更改器——GoLang 中的 CLI 工具

我是如何为一项琐碎的工作任务创建一个简单的工具的,你也可以上周我开始玩GoLang,它是一种由Google制作的类C编译语言,非常轻量和快速,事实上它经常在Techempower的基准测...

Go (Golang) 中的 Channels 简介(golang channel长度和容量)

这篇文章重点介绍Channels(通道)在Go中的工作方式,以及如何在代码中使用它们。在Go中,Channels是一种编程结构,它允许我们在代码的不同部分之间移动数据,通常来自不同的goro...

Golang引入泛型:Go将Interface「」替换为“Any”

现在Go将拥有泛型:Go将Interface{}替换为“Any”,这是一个类型别名:typeany=interface{}这会引入了泛型作好准备,实际上,带有泛型的Go1.18Beta...

一文带你看懂Golang最新特性(golang2.0特性)

作者:腾讯PCG代码委员会经过十余年的迭代,Go语言逐渐成为云计算时代主流的编程语言。下到云计算基础设施,上到微服务,越来越多的流行产品使用Go语言编写。可见其影响力已经非常强大。一、Go语言发展历史...

Go 每日一库之 java 转 go 遇到 Apollo?让 agollo 来平滑迁移

以下文章来源于GoOfficialBlog,作者GoOfficialBlogIntroductionagollo是Apollo的Golang客户端Apollo(阿波罗)是携程框架部门研...

Golang使用grpc详解(golang gcc)

gRPC是Google开源的一种高性能、跨语言的远程过程调用(RPC)框架,它使用ProtocolBuffers作为序列化工具,支持多种编程语言,如C++,Java,Python,Go等。gR...

Etcd服务注册与发现封装实现--golang

服务注册register.gopackageregisterimport("fmt""time"etcd3"github.com/cor...

Golang:将日志以Json格式输出到Kafka

在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:https://github.com/...

如何从 PHP 过渡到 Golang?(php转golang)

我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗旨,从零开始,开始学习。因为我司没有专门的Golang大牛,所以我也只能一步步自己去...