vue3的宏到底是什么东西?
前言
从vue3开始vue引入了宏,比如defineProps、defineEmits等。我们每天写vue代码时都会使用到这些宏,但是你有没有思考过vue中的宏到底是什么?为什么这些宏不需要手动从vue中import?为什么只能在setup顶层中使用这些宏?
vue 文件如何渲染到浏览器上
要回答上面的问题,我们先来了解一下从一个vue文件到渲染到浏览器这一过程经历了什么?
我们的vue代码一般都是写在后缀名为vue的文件上,显然浏览器是不认识vue文件的,浏览器只认识html、css、jss等文件。所以第一步就是通过webpack或者vite将一个vue文件编译为一个包含render函数的js文件。然后执行render函数生成虚拟DOM,再调用浏览器的DOM API根据虚拟DOM生成真实DOM挂载到浏览器上。

vue3的宏是什么?
我们先来看看vue官方的解释:
宏是一种特殊的代码,由编译器处理并转换为其他东西。它们实际上是一种更巧妙的字符串替换形式。
宏是在哪个阶段运行?
通过前面我们知道了vue 文件渲染到浏览器上主要经历了两个阶段。
第一阶段是编译时,也就是从一个vue文件经过webpack或者vite编译变成包含render函数的js文件。此时的运行环境是nodejs环境,所以这个阶段可以调用nodejs相关的api,但是没有在浏览器环境内执行,所以不能调用浏览器的API。
第二阶段是运行时,此时浏览器会执行js文件中的render函数,然后依次生成虚拟DOM和真实DOM。此时的运行环境是浏览器环境内,所以可以调用浏览器的API,但是在这一阶段中是不能调用nodejs相关的api。
而宏就是作用于编译时,也就是从vue文件编译为js文件这一过程。
举个defineProps的例子:在编译时defineProps宏就会被转换为定义props相关的代码,当在浏览器运行时自然也就没有了defineProps宏相关的代码了。所以才说宏是在编译时执行的代码,而不是运行时执行的代码。
一个defineProps宏的例子
我们来看一个实际的例子,下面这个是我们的源代码:
<template>
<div>content is {{ content }}</div>
<div>title is {{ title }}</div>
</template>
<script setup lang="ts">
import {ref} from "vue"
const props = defineProps({
content: String,
});
const title = ref("title")
</script>
在这个例子中我们使用defineProps宏定义了一个类型为String,属性名为content的props,并且在template中渲染content的内容。
我们接下来再看看编译成js文件后的代码,代码我已经进行过简化:
import { defineComponent as _defineComponent } from "vue";
import { ref } from "vue";
const __sfc__ = _defineComponent({
props: {
content: String,
},
setup(__props) {
const props = __props;
const title = ref("title");
const __returned__ = { props, title };
return __returned__;
},
});
import {
toDisplayString as _toDisplayString,
createElementVNode as _createElementVNode,
Fragment as _Fragment,
openBlock as _openBlock,
createElementBlock as _createElementBlock,
} from "vue";
function render(_ctx, _cache, $props, $setup) {
return (
_openBlock(),
_createElementBlock(
_Fragment,
null,
[
_createElementVNode(
"div",
null,
"content is " + _toDisplayString($props.content),
1 /* TEXT */
),
_createElementVNode(
"div",
null,
"title is " + _toDisplayString($setup.title),
1 /* TEXT */
),
],
64 /* STABLE_FRAGMENT */
)
);
}
__sfc__.render = render;
export default __sfc__;
我们可以看到编译后的js文件主要由两部分组成,第一部分为执行defineComponent函数生成一个 __sfc__ 对象,第二部分为一个render函数。render函数不是我们这篇文章要讲的,我们主要来看看这个__sfc__对象。
看到defineComponent是不是觉得很眼熟,没错这个就是vue提供的API中的 definecomponent函数。这个函数在运行时没有任何操作,仅用于提供类型推导。这个函数接收的第一个参数就是组件选项对象,返回值就是该组件本身。所以这个__sfc__对象就是我们的vue文件中的script代码经过编译后生成的对象,后面再通过__sfc__.render = render将render函数赋值到组件对象的render方法上面。
我们这里的组件选项对象经过编译后只有两个了,分别是props属性和setup方法。明显可以发现我们原本在setup里面使用的defineProps宏相关的代码不在了,并且多了一个props属性。没错这个props属性就是我们的defineProps宏生成的。

我们再来看一个不在setup顶层调用defineProps的例子:
<script setup lang="ts">
import {ref} from "vue"
const title = ref("title")
if (title.value) {
const props = defineProps({
content: String,
});
}
</script>
运行这个例子会报错:defineProps is not defined
我们来看看编译后的js代码:
import { defineComponent as _defineComponent } from "vue";
import { ref } from "vue";
const __sfc__ = _defineComponent({
setup(__props) {
const title = ref("title");
if (title.value) {
const props = defineProps({
content: String,
});
}
const __returned__ = { title };
return __returned__;
},
});
明显可以看到由于我们没有在setup的顶层调用defineProps宏,在编译时就不会将defineProps宏替换为定义props相关的代码,而是原封不动的输出回来。在运行时执行到这行代码后,由于我们没有任何地方定义了defineProps函数,所以就会报错defineProps is not defined。
总结
现在我们能够回答前面提的三个问题了。
vue中的宏到底是什么?vue3的宏是一种特殊的代码,在编译时会将这些特殊的代码转换为浏览器能够直接运行的指定代码,根据宏的功能不同,转换后的代码也不同。为什么这些宏不需要手动从
vue中import?因为在编译时已经将这些宏替换为指定的浏览器能够直接运行的代码,在运行时已经不存在这些宏相关的代码,自然不需要从
vue中import。为什么只能在
setup顶层中使用这些宏?因为在编译时只会去处理
setup顶层的宏,其他地方的宏会原封不动的输出回来。在运行时由于我们没有在任何地方定义这些宏,当代码执行到宏的时候当然就会报错。
如果想要在vue中使用更多的宏,可以使用 vue macros。这个库是用于在vue中探索更多的宏和语法糖,作者是vue的团队成员 三咲智子 。
如果我的文章对你有点帮助,欢迎关注公众号:【欧阳码农】,文章在公众号首发。你的支持就是我创作的最大动力,感谢感谢!
vue3的宏到底是什么东西?的更多相关文章
- CPU到底是什么东西?它为什么能够执行数学运算?
CPU到底是什么东西?它为什么能够执行数学运算? 本文地址http://yangjianyong.cn/?p=20转载无需经过作者本人授权 简单的物理电路 先来看一张初中学过的物理电路图: 从图中我们 ...
- 关于RundownProtect到底是什么东西
RundownProtect这个字段相信只要是读过WRK源码的都会看过这个东西,这个字段在进程和线程的结构中都存在.最典型的例子就是对进程要进行什么操作的时候会先引用这个字段进行加保护,等操作结束后再 ...
- JS事件处理函数中return false到底是什么东西
在<JS DOM编程艺术>一书中,用return false来阻止事件默认行为,可是js高程3里没有这种用法,那这到底是什么呢. 先看一下知乎的一个解释 就此问题,首先要纠正两个观点: 1 ...
- ESB企业服务总线到底是什么东西呢?
顾名思义,企业服务总线(ESB)就是一条企业架构的总线,所有的企业服务都挂接到该总线上对外公布,企业服务总线负责管理服务目录,解析服务请求者的请求方法.消息格式,并对服务提供者进行寻址,转发服务请求. ...
- vue3和vue2 的区别,vue3和vu2到底哪个好呢?
vue3 正式发布有两年多了,之前也做过一些学习和研究.vue3 发布后给某培训机构开发了一套vue3课程课件,自己也开源了一套基于vue3的后台管理系统(因为个人懒的原因,半年后才上传到gitHub ...
- php单元测试到底是什么东西呢?
前言: 真正写php代码也有3年时间了,勉强算是一个php程序员, 但是,心底却一直没有底气. 都说测试驱动开发,可我连程序开发中什么是单元测试?这种基本的程序员的素养都 还不是很清楚,痛定思痛,决定 ...
- Linux 内核常见宏定义
我们在阅读Linux内核是,常见到这些宏 __init, __initdata, __initfunc(), asmlinkage, ENTRY(), FASTCALL()等等.它们定义在 /incl ...
- 嵌入式C语言自我修养 04:Linux 内核第一宏:container_of
4.1 typeof 关键字 ANSI C 定义了 sizeof 关键字,用来获取一个变量或数据类型在内存中所占的存储字节数.GNU C 扩展了一个关键字 typeof,用来获取一个变量或表达式的类型 ...
- extern,头文件和ifndif宏
转自:CSDN->fpmystar 用#include可以包含其他头文件中变量.函数的声明,为什么还要extern关键字,如果我想引用一个全局变量或函数f(),我只要直接在源文件中包含#incl ...
- WmS详解(一)之token到底是什么?基于Android7.0源码
做Android有些年头了,Framework层三大核心View系统,WmS.AmS最近在研究中,这三大块,每一块都够写一个小册子来介绍,其中View系统的介绍,我之前有一个系列的博客(不过由于时间原 ...
随机推荐
- ApplicationContextAware 的理解和应用
当我们在项目中获取某一个spring bean时,可以定义一个类,实现ApplicationContextAware 该接口,该接口可以加载获取到所有的 spring bean. package c ...
- 通过 DBCA 创建 Oracle Database 21c 的进度停滞在 36%
1.问题 安装过程中一直卡在36% 检查 dbca 日志文件 位于 H:\app\trmbh\cfgtoollogs\dbca\ORCL\trace.log_2023-09-12_12-04-20PM ...
- [转帖]idea配置tomcat参数,防止nvarchar保存韩文、俄文、日文等乱码
描述下我的场景: 数据库服务器在远程机器上,数据库使用的Oracle,字符集是ZHS16GBK,但保存韩文.俄文.日文等字段A的数据类型是nvarchar(120),而nvarchar使用的是Unic ...
- [转帖]配置cri-docker使kubernetes1.24以docker作为运行时
从kubernetes 1.24开始,dockershim已经从kubelet中移除,但因为历史问题docker却不支持kubernetes主推的CRI(容器运行时接口)标准,所以docker不能再作 ...
- [转帖]关于UNDO
原文地址:https://www.modb.pro/db/70802?xzs= 一:请描述什么是Oracle Undo. 二:请描述UNDO的作用. 三:请谈谈你对Manual Undo Manage ...
- [转帖] TiDB 产品体系介绍
https://www.modb.pro/db/521269#:~:text=%E4%BC%81%E4%B8%9A%E7%89%88%E5%92%8C%E7%A4%BE%E5%8C%BA%E7%89% ...
- [转帖]一、Kafka Tool使用
一.Kafka Tool使用 1.添加cluster 2.开启SASL_PLAINTEXT 如果kafka 开启SASL_PLAINTEXT认证(用户名和密码认证) 3.高级设置 如果设置的是SASL ...
- [转帖]第5章 WINDOWS PE/COFF
https://www.jianshu.com/p/35db9df2514f?utm_campaign=maleskine&utm_content=note&utm_medium=se ...
- 在线安装gfortran的方法-CentOS8 or 阿里龙蜥
在线安装gfortran的方法-CentOS8 or 阿里龙蜥 背景 在阿里云上面进行了 speccpu2006的测试验证 但是发现总是很多包安装不过去 原因是阿里最小化安装的龙蜥系统. 缺少很多编译 ...
- JDK内嵌指令的简单学习
java 可以使用 java -jar的方式启动服务 日常工作中用到的比较少 javac 可以将.java 文件编译成 .class中间代码 这个工具开发编写代码中是经常需要使用的, jenkins ...