谈谈 Vue 模板和 JSX
工具链
从学习曲线角度来讲,结合我个人体会,React 学习路线是比 Vue 陡峭的,这个和 JSX、Template 有关吗?当然有。在 React 中使用 JSX,众所周知, JSX 需要经过 Transform 才能在浏览器中运行。马上就有小伙伴反驳了,Vue 有官方的 Vue-cli, React 使用 create-react-app 初始化项目就好了呀,并不需要比 Vue 多学习其他工具呀。
我们从另一个角度来看这个问题,使用 JSX 还需要熟练 ESM,这是绕不开的,因为一个 React 组件就是一个 js 或 JSX,这可能会给新手带来疑惑,组件是如何链接的?先别着急反驳,接着往下看。
仅仅掌握“三剑客”的新手就可以轻松上手 Vue,这在 Vue 官方文档中有所体现。
巧妙之处就在与上图中的 “易用”,仅仅学会了 HTML、CSS、JavaScript 就能上手。Vue 的“渐进式”不仅体现在跟随项目的复杂度上的,还有很大程度上适应使用者的水平。这不是空穴来风,当年鄙人就仅学习了这“三剑客”,就用 Vue-cli 初始化并完成了小项目。如今我思考在当时 Vue 是如何帮我避开 ESM 的。答案在于 vue 的“三段式结构”。
<script>
export defalut {
// ...
}
</script>
我的注意点完全在于导出的这个对象之中以及上方的 Template 和下方的 Style,只知道在这个对象里面写一些 Data、Methods 等等。甚至完全没有在意 export defalut
这个关键字。
不仅如此,Vue 的 Template + Options API 基本就规范了处理一些逻辑时的大体形式,这在通过搜索引擎检索一些遇到的问题时,通常能够轻易看懂检索到的代码,甚至可以“依葫芦画瓢”,这对新手无疑是一个优势。相比 JSX, 写法上,Template 虽不能够从“优雅”上胜出,但 JSX 更容易带入个人编码风格,这应该能使大家有所认同,这也就加大了新手的理解难度。
回到问题,那么 Vue 是如何引入组件的呢?作为新手,我只会“依葫芦画瓢”,通过一条 import 语句导入进来,然后在 components 里面将组件注册,这一切都被我自然得误认为是 Vue 的能力。
这不代表使用 Vue 不需要学习 ESM,没错,这是究极必要的,熟悉 ESM 可以更好得组织项目代码。上面我只是在思考当年 Vue 是怎么帮我避开 ESM 的,或者说我作为新手时是如何毫无察觉地避开它的,Template “功不可没”。
题外话,Vue 的 Template 可以放到 Script 标签下方,这可能更符合 React 用户的直觉,看尤大在推上分享一些 Demo 时有时会这么写。如果您乐意,也可以这么做,但在多人协作的项目中还要考虑小伙伴的感受。
<script>
export defalut {
// ...
}
</script>
<template>
</template>
Vue + JSX = React?
所谓“萝卜白菜,各有所爱”。在 React 中只能使用 JSX,Vue 从 2.0 开始干脆把 JSX 也支持完事了。有人说,在 Vue 中使用 JSX 为什么不直接使用 react? 这个话题就大了,这不仅和项目的技术选型有关,且 Vue 和 React 设计上就有很大差别。在 Vue 中无论使用 Template 还是 JSX 都会被编译成 h 函数(在 Vue 2 中称为 render 函数)。所以,在 Vue 中使用 JSX,只是换了一种表现形式而已。
我们来看一下 Vue 将 Template 渲染到浏览器的过程。
<div>Hello</div>
这个HTML也可以通过一个虚拟节点 VNode 来表示,也就是用 JavaScript 对象的形式来表示。
{
tag: 'div',
children: [
{
text: 'Hello'
}
]
}
Vue 知道如何将此虚拟节点并挂载到 DOM 上,它会更新我们在浏览器中看到的内容,但是 VNode 从哪里来的呢?实际还有一个步骤,Vue 基于我们的 Template 创建一个渲染函数,返回一个虚拟 DOM 节点。
渲染函数可以是这样的:
render(h) {
return h('div', 'hello')
}
当组件更改时,Render 函数将重新运行,它将创建另一个虚拟节点。然后发送旧的 VNode 和新的 VNode 到 Vue中进行比较并以最高效的方式在我们的网页上更新。例如下图所示,仅仅更新了文本内容。
题外话,实际 Vue 有三个核心模块:
- Reactivity Module 响应式模块
- Compiler Module 编译器模块
- Renderer Module 渲染模块
响应式模块允许创建 JavaScript 响应对象并可以观察其变化。当使用对象的代码运行时,它们会被跟踪,因此,它们可以在响应对象发生变化后运行。
编译器模块获取 HTML 模板并将它们编译成渲染函数。这可能在运行时在浏览器中发生,但在构建 Vue 项目时更常见。这样浏览器就可以只接收渲染函数。
渲染模块在网页上渲染组件经历三个不同阶段:在渲染阶段,将调用 render 函数,它返回一个虚拟 DOM 节点;在挂载阶段,使用虚拟 DOM 节点并调用 DOM API 来创建网页;在补丁阶段,渲染器将旧的虚拟节点和新的虚拟节点进行比较并只更新变化的部分。
上面是 Vue 将 Template 渲染到浏览器的过程,和 Template 类似,在 Vue 中使用的 JSX 也会转化成 h 函数,眼见为实。
所以,了解这个过程,您可能不是那么排斥在 Vue 中使用 JSX 了,或者或许对它在 Vue 中的表现不是那么陌生了。
从另一个方面来讲,Vue 中的 JSX 和 React 中的 JSX 在写法上也有差别。在 Vue JSX 中您可以直接使用熟悉的指令(directives),例如 Vue 内置的 v-show
、 v-model
甚至 v-models
和自定义指令,但例如 slots 在 Vue JSX 中或许没有在 React 中那么方便。
“联合”的能力
在 Vue sfc(single file component)中同时编辑 script、template、style,这提供了“联合”的能力,即在一个文件中使 Style 和 Template 共享 Script,帮助开发者更容易实现业务。例如:rfcs-style-variables,该提案虽然还没有最终确定下来,但 Vue 展示了这种能力。基础示例:
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data:()=> ({
color: 'red',
font: {
size: '2em'
}
})
}
</script>
<style>
.text {
color: v-bind(color);
/* expressions (wrap in quotes) */
font-size: v-bind('font.size');
}
</style>
通过 style-variables 写有一个有趣的示例,此处为部分代码。
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const inputBorderColor = ref('')
const onEngineChange = engine => {
for (const { name, color } of enginesData) {
if (name === engine) {
inputBorderColor.value = color
return
}
}
}
return {
inputBorderColor,
}
},
})
</script>
<style lang="scss">
input {
&:focus {
border-color: v-bind(inputBorderColor);
}
}
</style>
如果在 Vue 中使用 JSX, 就无法利用这个优势了。题外话,在 React 中类似的 css-in-js 方案是 styled-component。
业务组件库
Vue 几乎所有面向业务构建的生态内容给出的示例代码都是基于 Template 的。我们通常在项目中安装 UI 组件库依赖,组件库中给出的示例代码也是基于 Template 的。当前 Vue 组件库文档示例代码正在由 Options API 向 Composition API 过渡,但几乎没有可能从 Template 向 JSX 过渡,或者向用户提供 JSX 的组件示例代码。这非常重要,如果您的项目依赖组件库,查看文档后还需要将 Template 转到 JSX,这无疑增加开发成本。
TypeScript 支持
在 script 中,vue3 相比 vue2 已经出现质的飞跃。从 Template 来看,Vue 还有待完善,但这个可行的。JSX 一开始也没有类型支持,完全是 TS 给加了一套针对 JSX 的推导机制。
模版和类型推导,表面上看,隔了一层模版语法 + 编译,似乎确实存在 “断层”,但其实里面没您想的差那么远。Vue 的模版是编译成 virtual dom 渲染函数的,生成的 js 跟 React 的渲染函数一样可以类型推导,而模版跟生成的 js 之间是完整的逻辑映射,所以这里其实主要是需要做一些工具链上的衔接,把对生成的 js 分析出来的 intellisense 反馈到 IDE 里的模版上。技术上是完全可行的。
vscode 插件 Volar 已经支持 Template 表达式的类型检查。Vetur 虽然不支持还未定稿的 RFC,也已经支持基于现有 API 的模板类型检查和组件 props 类型检查了。另外,在 vue3 中无论是否使用 TS,通过 defineComponent 定义组件都能获得更好的提示。
可以预见的是,Vue 从升级 3.0 后,对于 TypeScript 的支持将会越来越好。
适用场景
在大多数场景下(尤其是业务场景)使用 Template 可能是更好的选择, vue3 基于 Template 分析做了大量的优化,而使用 JSX 需要手动做一些优化。
JSX 由于更具灵活性,通常一些组件库的不二之选,例如:Ant Design Vue、Vant、Element Plus(部分使用)。看到这么个例子: 根据 props 上的 reverse 属性,决定是否要调换两块内容的顺序。使用 JSX 轻易就能实现,且可读性也很高。
const renderContent = () => {
const Content = [
<div class="foo">Foo DOM...</div>,
<div class="bar">Bar DOM...</div>,
];
if (props.reverse) Content.reverse();
return <div>{Content}</div>;
}
如果通过模板来实现,在不抽象子组件的情况下,foo 和 bar 的模板结构需要重复写两遍,才能满足这个需求:
<template>
<div>
<template v-if="reverse">
<div class="bar">Bar DOM...</div>
<div class="foo">Foo DOM...</div>
</template>
<template v-else>
<div class="foo">Foo DOM...</div>
<div class="bar">Bar DOM...</div>
</template>
</div>
</template>
因此,在动态性强的场景下,JSX 会有一定优势。Composition API + JSX 是某些场景下追求极致的选择,相应地需要付出更多开发成本。
参考资料:
[1] https://www.zhihu.com/question/436260027/answer/1647182157
[2] https://www.zhihu.com/question/310485097/answer/591869966
[3] https://www.cnblogs.com/guangzan/p/13358322.html
谈谈 Vue 模板和 JSX的更多相关文章
- 西安电话面试:谈谈Vue数据双向绑定原理,看看你的回答能打几分
最近我参加了一次来自西安的电话面试(第二轮,技术面),是大厂还是小作坊我在这里按下不表,先来说说这次电面给我留下印象较深的几道面试题,这次先来谈谈Vue的数据双向绑定原理. 情景再现: 当我手机铃声响 ...
- 谈谈Vue.js——vue-resource全攻略
本篇文章主要介绍了谈谈Vue.js——vue-resource全攻略,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 概述 上一篇我们介绍了如何将$.ajax和Vue. ...
- 在vue中使用jsx语法
什么是JSX? JSX就是Javascript和XML结合的一种格式.React发明了JSX,利用HTML语法来创建虚拟DOM.当遇到<,JSX就当HTML解析,遇到{就当JavaScript解 ...
- 在Vue中使用JSX,很easy的
摘要:JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javasc ...
- sublime SublimeTmpl 添加vue模板
sublime2安装时候报错在control中加下面的代码 重新启动,可以进行安装 import urllib2,os; pf='Package Control.sublime-package'; i ...
- Vue模板内容
前面的话 如果只使用Vue最基础的声明式渲染的功能,则完全可以把Vue当做一个模板引擎来使用.本文将详细介绍Vue模板内容 概述 Vue.js使用了基于HTML的模板语法,允许声明式地将DOM绑定至底 ...
- Vue模板逻辑
前面的话 上一篇介绍了Vue的模板内容,而对于一般的模板引擎来说,除了模板内容,还包括模板逻辑.常用的模板逻辑包括条件和循环.本文将详细介绍Vue模板逻辑 条件渲染 在Vue中,实现条件逻辑依靠条件指 ...
- (英文版)VScode一键生成.vue模板
1. 安装vscode,官网地址 2.安装一个插件,识别vue文件 插件库中搜索Vetur,下图中的第一个,点击安装(Install) 3.新建代码片段 点击Code(代码)-Preferences( ...
- vscode写vue模板--代码片段
Ctrl+Shift+P打开命令输入 snippet (打开用户代码片段) 在输入vue(选择代码片段的语言) 如果搜索不到,安装一个插件 vueHelper 如果搜索到复制粘贴以下代码 { &quo ...
随机推荐
- 【手把手学习flutter】Flutter打Android包的基本配置和包体积优化策略
[手把手学习flutter]Flutter打Android包的基本配置和包体积优化策略 关注「松宝写代码」,回复"加群" 加入我们一起学习,天天向上 前言 因为最近参加2020FE ...
- MySQL ERROR 1040: Too many connections
如题,本章主要讲下当服务器出现 ERROR 1040: Too many connections错误时的一些处理心得. max_connections查看 ## 查看最大连接数 SHOW VARIAB ...
- vulnstack靶机实战01
前言 vulnstack是红日安全的一个实战环境,地址:http://vulnstack.qiyuanxuetang.net/vuln/detail/2/最近在学习内网渗透方面的相关知识,通过对靶机的 ...
- 单次期望 O(1) 的RMQ
膜万弘,太强了!!! 刚刚变态的zjjws想要将一个需要 \(RMQ\) 问题的时间和空间都卡成 \(O(n)\) ,就在可怜的蒟蒻 Point_King 一筹莫展之时万弘他出现了,给予了本蒟蒻光明和 ...
- rsync 参数说明及使用参数笔记好文摘抄
一.前言 最近发现rsync挺好用的--不过参数有点多,所以这儿写一篇给自己以后要用的时候做个参考. 二.参数说明 这儿全是我翻资料连蒙带猜(有些实在是不好解释)翻译出来的,请各位转载的留个名啊,虽然 ...
- GaussDB(DWS)磁盘维护:vacuum full执行慢怎么办?
摘要:在数据库中用于维护数据库磁盘空间的工具是VACUUM,其重要的作用是删除那些已经标示为删除的数据并释放空间. vacuum的功能 回收空间 数据库总是不断地在执行删除,更新等操作.良好的空间管理 ...
- 第一篇:docker 简单入门(一)
本篇目录 写在最前面的话 docker概念介绍 镜像的概念.容器的概念 docker的安装介绍 写在最前面的话 由于此类文章博客园鉴定为简单文章,所以已经移到csdn[https://blog.csd ...
- [日常摸鱼][poj2777]Count Color-线段树
辣鸡会考考完啦哈哈哈哈 题意:一块板分成$L$块,每次给一段连续的块染色或者询问一段有几种颜色,颜色的范围$\leq 30$ 我记得我好像做过一个类似的二维染色的问题-不过那个用树状数组直接过掉了- ...
- XCTF EasyHook
无壳,使用IDA直接分析主函数 逻辑很简单,问题的关键是Hook,题目也是EasyHook, 会发现在生成文件后,文件内容是被加密后的,那就怀疑加密函数参与Hook 动态调试一步步来看,先进入4012 ...
- phpstorm ext-json is missing in composer.json