Vue3中defineEmitsdefineProps 是怎么做到不用引入就能直接用的

Posted 码农小宋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue3中defineEmitsdefineProps 是怎么做到不用引入就能直接用的相关的知识,希望对你有一定的参考价值。

最近正在将一个使用单文件组件的 Options API 的 Vue2 javascript 项目升级为 Vue3 typescript,并利用 Composition API 的优势。

比如,下面这种 选项API 方式:

export default 
props:
name:
type: String,
required: true.

,
emits: [someEvent, increaseBy]
;

我们将它转成 组合API 方式:

const props = defineProps<
name: string;
>();
const emit = defineEmits<
(event: someEvent): void;
(event: increaseBy, value: number): void;
>();

从 选项API 的 ​emit​ 和 ​props​ 到 组合API 的 ​defineemit​ 和 ​defineProps​ 函数的基于类型语法的转换并不简单。我也很好奇 Vue 是如何处理接口的。


TypeScript 接口是只在设计和编译时存在的结构。它们在JavaScript运行时之前被过滤掉,那么它们是如何影响组件的行为的呢?

我想知道是否有办法看到Vue如何解释传递给 defineEmits 和 defineProps 的通用参数。如果你注意到文档中说你不需要导入 defineEmits 和 defineProps 函数。这是因为它们实际上是同名的JavaScript函数的宏。在进行完整的 TypeScript 传递之前,Vue webpack插件使用TypeScript的 AST(抽象语法树)来推导JavaScript版本的函数选项。

如果不是因为宏:

defineProps<
prop1: string;
prop2: number;
>();

就会变成:

defineProps();

这样就会导致参数缺失的错误。

如果看一下Vue的 SFC(单文件组件)编译器源代码,有一个叫做 compileScript 的函数。我开始尝试用最少的参数来调用这个函数,这样就不会出错,并模拟任何不重要的必要参数。最终发现了另一个叫 parse 的函数。这给了我所需的大部分参数,只剩下要mock的组件 id

这里有一个小脚本,它接收SFC的 .vue文件并输出 Vue 如何解释 TypeScript。

import  readFile, writeFile  from "fs";
import parseArgs from "minimist";
import parse, compileScript from "@vue/compiler-sfc";
const file, out = parseArgs(process.argv.slice(2),
string: ["file", "out"],
alias:
file: "f",
out: "o"

);
const filename = file;
const mockId = "xxxxxxxx";
readFile(filename, "utf8", (err, data) =>
const descriptor = parse(data,
filename
);
const content = compileScript(descriptor,
inlineTemplate: true,
templateOptions:
filename
,
id: mockId
);
if (out)
writeFile(out, "utf8", content);
else
process.stdout.write(content);

);

事例地址:https://stackblitz.com/edit/node-fzuykn?file=index.js

例如,有如以下组件:

interface Bar 
prop1: string;
prop2: number;


defineProps<
bar: Bar;
bars: Bar[];
asdf1?: boolean;
asdf2: string[];
>();

输出:

interface Bar 
prop1: string;
prop2: number;


export default /*#__PURE__*/_defineComponent(
__name: demo,
props:
bar: type: Object, required: true ,
bars: type: Array, required: true ,
asdf1: type: Boolean, required: false ,
asdf2: type: Array, required: true
,
setup(__props: any)
return (_ctx: any,_cache: any) =>
return (_openBlock(), _createElementBlock("div"))

正如上面所看到的,SFC编译器采用TypeScript类型信息,并建立了 props 对象。原始类型是一对一的。接口变成对象,而 ? 可选语法驱动 required 的属性。

Vue3中defineEmits、defineProps

以上是关于Vue3中defineEmitsdefineProps 是怎么做到不用引入就能直接用的的主要内容,如果未能解决你的问题,请参考以下文章

vue3中computed计算属性函数

vue3对比vue2

vue2与vue3的区别

在 vue3 中是不是可以访问子组件槽中的根 DOM 元素?我正在尝试在 vue3 中使用第 3 方库(sortablejs)

Vue2和Vue3的区别

Vue3中使用图片查看组件 支持vue3的图片组件