面试题:React 和 Vue 是如何描述 UI 界面的?有一些什么样的区别?
标准且浅显的回答:
React 中使用的是 JSX,Vue 中使用的是模板来描述界面
前端领域经过长期的发展,目前有两种主流的描述 UI 的方案:
- JSX
- 模板
JSX 历史来源
JSX 最早起源于 React 团队。在 React 中所提供的一种类似于 XML 的 ES 语法糖:
js
const element = <h1>Hello</h1>
经过 Babel 编译之后,就会变成:
js
// React v17 之前
var element = React.createElement("h1", null, "Hello");
// React v17 之后
var jsxRuntime = require("react/jsx-runtime");
var element = jsxRuntime.jsx("h1", {children: "Hello"});
无论是 17 之前还是 17 之后,执行了代码后会得到一个对象:
js
{
"type": "h1",
"key": null,
"ref": null,
"props": {
"children": "Hello"
},
"_owner": null,
"_store": {}
}
这个其实就是大名鼎鼎的虚拟 DOM。
React 团队认为,UI 本质上和逻辑是有耦合部分的,例如:
- 在 UI 上面绑定事件
- 数据变化后通过 JS 去改变 UI 的样式或者结构
作为一个前端工程师,JS 是用得最多,所以 React 团队思考屏蔽 HTML,整个都用 JS 来描述 UI。因为这样做的话,可以让 UI 和逻辑配合得更加紧密,所以最终设计出来了类 XML 形式的 JS 语法糖
由于 JSX 是 JS 的语法糖(本质上就是 JS),因此可以非常灵活的和 JS 语法组合使用,例如:
- 在 if 或者 for 当中使用 jsx
- 将 jsx 赋值给变量
- 将 jsx 当作参数来传递
- 在一个函数中返回一段 jsx
示例代码
js
function App({isLoading}){
if(isLoading){
return <h1>loading...</h1>
}
return <h1>Hello World</h1>;
}
这种灵活性就使得 jsx 可以轻松的描述复杂的 UI,如果和逻辑配合,还可以描述出复杂 UI 的变化。
使得 React 社区的早期用户可以快速实现各种复杂的基础库,丰富社区生态。又由于生态的丰富,慢慢吸引了更多的人来参与社区的建设,从而源源不断的形成了一个正反馈。
模板的历史来源
模板的历史就要从后端说起。
在早期前后端未分离的时候,最流行的方案就是使用模板引擎。模板引擎可以看作是在正常的 HTML 上面进行挖坑(不同的模板引擎语法不一样),挖了坑之后。服务器端会将数据填充到挖了坑的模板里面,生成对应的 html 页面返回给客户端。
所以在那个时期前端人员的工作,主要是 html、css 和一些简单的 js 特效(轮播图、百叶窗...)。写好的 html 是不能直接用的,需要和后端确定用的是哪一个模板引擎,接下来将自己写好的 html 按照对应模板引擎的语法进行挖坑
不同的后端技术对应的有不同的模板引擎,甚至同一种后端技术,也会对应很多种模板引擎,例如:
- Java (JSP、Thymeleaf、Velocity、Freemarker)
- PHP (Smarty、Twig、HAML、Liquid、Mustache、Plates)
- Python (pyTenjin、Tornado.template、PyJade、Mako、Jinja2)
- node.js (Jade、Ejs、art-template、handlebars、mustache、swig、doT)
模板引擎代码片段
- twig 模板引擎
php
基本语法
{% for user in users %}
* {{ user.name }}
{% else %}
No users have been found.
{% endfor %}
指定布局文件
{% extends "layout.html" %}
定义展示块
{% block content %}
Content of the page...
{% endblock %}
- blade 模板引擎
php
<html>
<head>
<title>应用程序名称 - @yield('title')</title>
</head>
<body>
@section('sidebar')
这是 master 的侧边栏。
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
- EJS 模板引擎
html
<h1>
<%=title %>
</h1>
<ul>
<% for (var i=0; i<supplies.length; i++) { %>
<li>
<a href='supplies/<%=supplies[i] %>'>
<%= supplies[i] %>
</a>
</li>
<% } %>
</ul>
这些模板引擎对应的模板语法就和 Vue 里面的模板非常的相似。
现在随着前后端分离开发的流行,已经没有再用模板引擎的模式了,后端开发人员只需要书写数据接口即可。但是如果让一个后端人员来开前端的代码,那么 Vue 的模板语法很明显对于后端开发人员来讲要更加亲切一些。
最后我们做一个总结,虽然现在前端存在两种方式:JSX 和模板的形式都可以描述 UI,但是出发点是不同
-
模板语法的出发点是,既然前端框架使用 HTML 来描述 UI,那么我们就扩展 HTML。让 HTML 种能够描述一定程度的逻辑,也就是"从 UI 出发,扩展 UI,在 UI 中能够描述逻辑"。
-
JSX 的出发点,既然前端使用 JS 来描述逻辑,那么就扩展 JS,让 JS 也能描述 UI,也就是"从逻辑出发,扩展逻辑,描述 UI"。
这两者虽然都可以描述 UI,但是思路或者说方向是完全不同的,从而造成了整体框架架构上面也是不一样的。
真题解答
题目:React 和 Vue 是如何描述 UI 界面的?有一些什么样的区别?
参考答案
在 React 中,使用 JSX 来描述 UI。因为 React 团队认为UI 本质上与逻辑存在耦合的部分,作为前端工程师,JS 是用的最多的,如果同样使用 JS 来描述 UI,就可以让 UI 和逻辑配合的更密切。
使用 JS 来描述页面,可以更加灵活,主要体现在:
- 在 if 语句和 for 循环中使用 JSX
- 将 JSX 赋值给变量
- 可以把 JSX 当作参数传入
- 在函数中返回 JSX
而模板语言的历史则需要从后端说起。早期在前后端未分离时代,后端有各种各样的模板引擎,其本质是扩展了 HTML,在 HTML 中加入逻辑相关的语法,之后在动态的填充数据进去。
如果单看 Vue 中的模板语法,实际上和后端语言中的各种模板引擎是非常相似的。
总结起来就是:
模板语法的出发点是,既然前端框架使用 HTML 来描述 UI,那么就扩展 HTML 语法,使它能够描述逻辑,也就是"从 UI 出发,扩展 UI,在 UI 中能够描述逻辑"。
而 JSX 的出发点是,既然前端使用 JS 来描述逻辑,那么就扩展 JS 语法,让它能够描述 UI,也就是"从逻辑出发,扩展逻辑,描述 UI"。
虽然这两者都达到了同样的目的,但是对框架的实现产生了不同的影响。