• Vue3中defineEmits、defineProps 是怎么做到不用引入就能直接用的


     

     

    最近正在将一个使用单文件组件的 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 的属性。
  • 相关阅读:
    ASP.NET Core - 入口文件
    MySQL故障排查与生产环境优化
    氨基/羧基/醛基/苯肼基/磺酸基/醛基化改性交联修饰聚苯乙烯微球的研究
    【Java】节点流和处理流(BufferedReader和BufferedWriter)
    Mysql8关键字
    外包公司干了2个月,技术倒退两年...
    软件架构风格
    Python回归预测建模实战-支持向量机预测房价(附源码和实现效果)
    为什无线网络连上去了还是没有网络?
    如何搭建远程服务器-(cpolar)
  • 原文地址:https://www.cnblogs.com/houxianzhou/p/16623074.html