工具链

从学习曲线角度来讲,结合我个人体会,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 有三个核心模块:

  1. Reactivity Module 响应式模块
  2. Compiler Module 编译器模块
  3. 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的更多相关文章

  1. 西安电话面试:谈谈Vue数据双向绑定原理,看看你的回答能打几分

    最近我参加了一次来自西安的电话面试(第二轮,技术面),是大厂还是小作坊我在这里按下不表,先来说说这次电面给我留下印象较深的几道面试题,这次先来谈谈Vue的数据双向绑定原理. 情景再现: 当我手机铃声响 ...

  2. 谈谈Vue.js——vue-resource全攻略

    本篇文章主要介绍了谈谈Vue.js——vue-resource全攻略,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧   概述 上一篇我们介绍了如何将$.ajax和Vue. ...

  3. 在vue中使用jsx语法

    什么是JSX? JSX就是Javascript和XML结合的一种格式.React发明了JSX,利用HTML语法来创建虚拟DOM.当遇到<,JSX就当HTML解析,遇到{就当JavaScript解 ...

  4. 在Vue中使用JSX,很easy的

    摘要:JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javasc ...

  5. sublime SublimeTmpl 添加vue模板

    sublime2安装时候报错在control中加下面的代码 重新启动,可以进行安装 import urllib2,os; pf='Package Control.sublime-package'; i ...

  6. Vue模板内容

    前面的话 如果只使用Vue最基础的声明式渲染的功能,则完全可以把Vue当做一个模板引擎来使用.本文将详细介绍Vue模板内容 概述 Vue.js使用了基于HTML的模板语法,允许声明式地将DOM绑定至底 ...

  7. Vue模板逻辑

    前面的话 上一篇介绍了Vue的模板内容,而对于一般的模板引擎来说,除了模板内容,还包括模板逻辑.常用的模板逻辑包括条件和循环.本文将详细介绍Vue模板逻辑 条件渲染 在Vue中,实现条件逻辑依靠条件指 ...

  8. (英文版)VScode一键生成.vue模板

    1. 安装vscode,官网地址 2.安装一个插件,识别vue文件 插件库中搜索Vetur,下图中的第一个,点击安装(Install) 3.新建代码片段 点击Code(代码)-Preferences( ...

  9. vscode写vue模板--代码片段

    Ctrl+Shift+P打开命令输入 snippet (打开用户代码片段) 在输入vue(选择代码片段的语言) 如果搜索不到,安装一个插件 vueHelper 如果搜索到复制粘贴以下代码 { &quo ...

随机推荐

  1. python初次接触

    1.python有什么用或者能做什么? 可以做网站(比如 YouTube.豆瓣),可以做图片处理,可以做科学计算,也可以爬虫,甚至于游戏,学好Python后不用担心没有用武之地,Google就大量的在 ...

  2. 《MySQL慢查询优化》之SQL语句及索引优化

    1.慢查询优化方式 服务器硬件升级优化 Mysql服务器软件优化 数据库表结构优化 SQL语句及索引优化 本文重点关注于SQL语句及索引优化,关于其他优化方式以及索引原理等,请关注本人<MySQ ...

  3. flask中SQLAlchemy学习

    ------------------------------------2019-08-22 17:53:54更新------------------------------ SQLALchemy实在 ...

  4. Web前端-按钮点击效果(水波纹)

    这种效果可以由元素内嵌套canves实现,也可以由css3实现. Canves实现 网上摘了一份canves实现的代码,略微去掉了些重复定义的样式并且给出js注释,代码如下 第一种方法: html骨架 ...

  5. 题解-FJOI2018 领导集团问题

    题面 FJOI2018 领导集团问题 给一棵树 \(T(|T|=n)\),每个点有个权值 \(w_i\),从中选出一个子点集 \(P=\{x\in {\rm node}|x\in T\}\),使得 \ ...

  6. AcWing 407. 稳定的牛分配

    大型补档计划 题目链接 题目看的有点晕(语文差) 总体来说就是让每头牛找个谷仓,不能超过容量,最小化每头牛在的谷仓在自己心目中排名的极差. 显然这个最优性问题不好做,但是转换为判定性问题这就是一个标准 ...

  7. Python排序函数用法

    Python排序函数完美体现了Python语言的简洁性,对于List对象,我们可以直接调用sort()函数(这里称为"方法"更合适)来进行排序,而对于其他可迭代对象(如set,di ...

  8. (干货)构建镜像之Dockerfile

    Dockerfile是一个文本文件,记录了镜像构建的所有步骤. 饭提示:学习Dockerfile构建镜像,就是在学习Dockerfile文件构建的命令+shell脚本语句 Dockerfile简单介绍 ...

  9. Struts2 S2-061(CVE-2020-17530)漏洞复现

    0x00 漏洞简介 Apache Struts2框架是一个用于开发Java EE网络应用程序的Web框架.Apache Struts于2020年12月08日披露 S2-061 Struts 远程代码执 ...

  10. uniapp发布到微信小程序整改摘要

    uniapp作为跨端的利器,可同时发布到安卓.ios.微信小程序.支付宝小程序.百度小程序.头条小程序.QQ小程序等8个平台. 如果是轻量级的应用,不涉及太多功能的话,或许可以直接打包移植,但涉及前后 ...