前文我们了解了react的一些简单介绍,学习了一下如何使用react来完成Hello react的样例,简单探讨了一下react创建虚拟DOM的两种方法,以及为什么要使用jsx语法来创建虚拟DOM。当然除了以上我们所提及的内容之外,我们也简单探讨了一下虚拟DOM和真实DOM都是什么,以及这二者的一些区别。

因为我们已经明白了jsx存在的意义,那么我们这节课就来进一步了解一下jsx语法的基本规则。

回顾

在开始这节课内容的学习之前,我们对上节所学内容来做一个简单的回顾。

上节课我们都学了写什么呢?就是虚拟DOM和真实DOM。那么我们知道:

  • 虚拟DOM和真实DOM都是js对象
  • 虚拟DOM比真实DOM属性或者API数量要少,要更加轻量级
  • 虚拟DOM只在react内部使用,必须由react映射成真实DOM之后才能呈现在页面上

以上便是上节课的基本要点。那么接下来我们就进入本节课内容的学习——jsx的基本语法规则

jsx的相关概念

定义

jsx全称为JavaScrpt XML,这是由react定义的一种类似于XMLJavaScript扩展语法 即:JavaScript + XML。注意这里说了是js的扩展语法,也就是说jsx的语法核心还是js只不过扩展了一些新的语法。

jsx的本质

早在react创建虚拟DOM的两种方法那一小节中我们就曾经提起过,我们的jsx语法所写的代码最终会由babel库翻译成原生js语法,也就是会转换成React.createElement(compoment,props,...children)这种语法形式,也就是说jsx语法是React.createElement(compoment,props,...children)方法的语法糖。

jsx的作用

依然还是在react创建虚拟DOM的两种方法那一小节,我们说了,jsx存在的目的就是为了让我们能够更加方便的创建虚拟DOM,同时也为了我们的代码具有更好地可读性和可维护性。jsx语法具有以下几个要点:

  • 写法:var element = <h1><span>Hello jsx</span></h1>,如果有多行代码可以用()括起来
  • 这个等号右边的这一串不是字符串,也不是HTML/XML标签
  • 这个虚拟DOM最终产生的是一个js对象

jsx可用的标签名

jsx可以使用HTML标签,也可以使用其他标签

jsx语法基本运用

上面的那些概念全是冷冰冰的文字,没有什么意思,那么我们还是拿样例来说事儿。依然还是最简单的Hello react来做样例。

<!-- index.html -->
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Jsx rule</title>
</head>

<body>
  <div id="test"></div>

  <script src="../../static/js/babel.min.js"></script>
  <script src="../../static/js/react.development.js"></script>
  <script src="../../static/js/react-dom.development.js"></script>

  <script type="text/babel">
    // 1. 创建虚拟DOM
    const VDOM = ( // 这里创建虚拟DOM,切记不能用引号
      <h2 id="title">
        <span>Hello react</span>
      </h2>
    );
    // 2. 渲染虚拟DOM到页面
    ReactDOM.render(VDOM, document.getElementById("test"));
  </script>
</body>

</html>

jsx语法内混用js语法表达式

上面这段代码我们是不是都已经看腻了?实在是写了太多遍了。

但是呢我们把需求变更一下。如果我要<h2>标签的id属性以及<span>标签的内容全部都由变量传进来又应该怎么处理呢?

// 错误写法
let mainID = "title";
let mainData = "Hello react";
const VDOM = (
    <h2 id=mainID>
        <span>mainData</span>
    </h2>
);
ReactDOM.render(VDOM, document.getElementById("test"));

从上面这段代码来看我们很明显可以看出来这是绝对不可能实现我们想要的效果的,因为在这段代码里面常见虚拟DOM这一步是根本没有读取变量的。因为jsx语法不支持直接通过变量名来读取并变量。

但是如果我们的需求就是要读取并调用变量可怎么办呢?我们想也知道,在工作开发中是不可能把数据写死在程序里的,一定要用到变量的。

虽然说jsx不支持直接通过变量名来调用变量,那么我们就间接通过变量名来调用变量呗。jsx是支持使用js语法表达式的啊。但是需要通过{}来引入支持,那么就刚才的需求,我们知道该怎么处理了吧,就像下面这样:

// 正确写法
let mainID = "title";
let mainData = "Hello react";
const VDOM = (
    <h2 id={mainID}>
        <span>{mainData}</span>
    </h2>
);
ReactDOM.render(VDOM, document.getElementById("test"));

这次我们再看:

image-20211210155745087

这样便满足了我们的需求。

从而我们得出一个结论就是:jsx内需要通过{}来对js表达式进行支持。

jsx设定class属性

在日常开发中,我们也并不是就简单的把数据放在网页上就行了,有些时候我们会要求这批数据展示到页面上的时候要有一个统一的样式。

比如我们写好了一个统一的css,我们需要将相应的class属性加给指定标签,比如在这个样例里面我要把相应的class属性加给<h2>标签,这个需求该怎么处理呢?比如我已经在<style>标签里面写好了一段css

.title {
    background-color: orange;
    width: 200px;
}

按照我们习惯的HTML写法的话标签里肯定就直接写class属性了呗,就像这样:

// 错误写法
let mainID = "title";
let mainData = "Hello react";
const VDOM = (
    <h2 id={mainID} class="title">
        <span>{mainData}</span>
    </h2>
);

那我们来看一下效果。

image-20211210162421743

诶?有效果,既然有效果为啥我还在注释里标注了是错误写法呢?那我们打开控制台看一下,有一个报错信息。

image-20211210162815328

这个报错告诉我们class属性在当前DOM中不被允许,问我们想要用的是不是className属性。所以我们不妨大胆地臆测一下。我们是不是这么写就对了呢?

// 猜想
let mainID = "title";
let mainData = "Hello react";
const VDOM = (
    <h2 id={mainID} className="title">
        <span>{mainData}</span>
    </h2>
);

再看一下结果:

image-20211210163340893

这次就没有报错了,而且样式效果也出来了。

所以我们又得出一个结论就是:jsx任何标签中class属性的指定必须用className来指定

jsx给标签指定内联样式

刚才我们虽然说成功通过className属性让<h2>标签能够成功加载我们指定的样式,那么接下来,我哥我想要<span>标签也改变一下样式,我要它的文字颜色是白色,字体指定为20px该怎么写?

大家都知道可以用className,那么这里也加一个className属性然后再写一段css不就好了嘛,当然,这个方法可行。但是如果我这里仅仅就是这一块我想要用内联样式来写,又该怎么写呢?

// 错误写法
let mainID = "title";
let mainData = "Hello react";
const VDOM = (
    <h2 id={mainID} className="title">
        <span style="color: white;font-size: 20px;">{mainData}</span>
    </h2>
);

可能有人要说了,嗐,内联样式不就是style属性嘛,直接写不就好了嘛。那我们来试一试。

image-20211210164735895

啥都没显示,而且还出来了这么多的报错信息。但是这一堆信息是怎么说的呢?第一条信息告诉我们,<h2>标签中的<span>标签出现了错误。那么我们看第二条信息,信息中告诉我们style属性不能写字符串,也就是说jsx语法中的标签不支持把style属性写成字符串,但是后面给了我们提示说可以使用{{ }}这样的两层花括号来括起来。那么我们再来猜一下:

// 猜想
let mainID = "title";
let mainData = "Hello react";
const VDOM = (
    <h2 id={mainID} className="title">
        <span style={{color: "white", fontSize: "20px"}}>{mainData}</span>
    </h2>
);

然后再回头看一下效果:

image-20211210165448742

诶,这样就成功了。

但是为什么啊?我们来分析一下style={{color: "white"}}这一段是个什么意思啊?两层花括号里面是键值对。我们回忆一下,这个是不是看着很眼熟呢?我们似乎看见了一个很熟悉的结构:一层花括号里面存放键值对,这不就是js对象嘛,那么jsx中出现了一层花括号里面括着一个js对象的结构,那这不就是在jsx里面使用js表达式嘛。

但还有一点要注意,我设定的fontSize,可能大家也注意到了,我们正常在写css的时候不都是用font-size的嘛?为什么这里要写成小驼峰的方式了呢?

因为我们也说了,style属性里面其实是个对象。对象的key不支持这种用-符号连接起来的方式。

所以我们又由此得到一个结论就是:内联样式必须使用style={{key: value}}的方式来写

jsx根标签

上面我们说了那么多,到现在也就一个<h2>标签,但是我们日常所看到的的网页也不是就着一行<h2>元素啊,如果我想在h2标签下面再建一个同一层级的<h3>标签怎么办呢?

按照我们写HTML的习惯,是不是就直接在<h2>标签下面就直接写一个<h3>标签了啊就像这样:

// 错误写法
let mainID = "title";
let mainData = "Hello react";
const VDOM = (
  <h2 id={mainID} className="title">
    <span style={{ color: "white", fontSize: "20px" }}>{mainData}</span>
  </h2>
  <h3>Hello</h3>
);

但是呢,这样写对吗?我们从上面的代码上看着好像没有什么问题,因为我们写HTML就是这么写的啊,但是如果我们在 IDE里面写这么段代码的话可就不是这么一回事儿了。IDE会有很直观的报错提醒:

image-20211212111920999

而且报错信息里也说得很清楚,jsx表达式里面必须只能有一个父级元素。也就是说我们只能有一个根标签。电视现在来看<h2>标签和<h3>标签是同一个层级的,也就是说当前的这个jsx表达式有两个根标签。

那我们到底应该怎么处理才能个实现我们的需求呢?

既然说了只能有一个根标签,那么我们就只用一个根标签呗,我们像这样,用一个<div>标签把里面的两个标签给封装起来,这样不就成了只有一个根节点了嘛

let mainID = "title";
let mainData = "Hello react";
const VDOM = (
  <div>
    <h2 id={mainID} className="title">
      <span style={{ color: "white", fontSize: "20px" }}>{mainData}</span>
    </h2>
    <h3>Hello</h3>
  </div>
);

我们来看一下效果:

image-20211212114225310

这样我们就可以成功实现我们的需求了。

所以我们从以上内容有得出一个结论:虚拟DOM只允许有一个根标签。

虚拟DOM中添加input标签

可能说到了这里,大家觉得我会举一反三了,我要想在一个虚拟DOM里面天健多个标签,我都在最外层用<div>标签一括,然后在<div>标签里面直接写HTML就可以了。

不过呢……我们再来看一个案例,我现在想要一个输入框,让用户在下面自己随便输入点什么东西。是不是这么写就行了?

// 错误写法
let mainID = "title";
let mainData = "Hello react";
const VDOM = (
  <div>
    <h2 id={mainID} className="title">
      <span style={{ color: "white", fontSize: "20px" }}>{mainData}</span>
    </h2>
    <h3>Hello</h3>
    <input type="text">
  </div>
);

image-20211212115138191

依然还是给我报错了啊。跟我说input标签没有闭合,我们在写HTML的时候都知道大多数标签都是成对存在的,分别负责标签的开始与闭合,例如<div></div>,其中<div>便是开始标签,而</div>则是闭合标签。但是在HTML中某些标签就是独立存在的,没有闭合标签,也没有严格的闭合要求,比如<br>、<input>这两个标签我们可以写成<br />、<input />这种形式的自闭和标签,也可以不写。

但是react严格认为jsx中的标签要遵守标签的开闭原则,开始了就必须闭合,所以说我们可以在jsx中把input这一类标签写成自闭合形式,而且,jsx支持<input></input>这种形式来闭合标签。

所以上面的代码可以修改为:

let mainID = "title";
let mainData = "Hello react";
const VDOM = (
  <div>
    <h2 id={mainID} className="title">
      <span style={{ color: "white", fontSize: "20px" }}>{mainData}</span>
    </h2>
    <h3>Hello</h3>
    <input type="text" /> // 或者 <input type="text"></input>
  </div>
);

所以我们得到一个结论:虚拟DOM中的任何一个标签都必须闭合。

jsx中的标签

通过以上的一些案例,我们应该都多多少少能写一点网页出来了,但是我们是不是啥都能往里面写呢?在外面写HTML的时候我们会发现这样一件事,就是我们不论往HTML文件里面写什么,页面基本都能展示出来。但是jsx也可以嘛?

比方说下面这段代码:

let mainID = "title";
let mainData = "Hello react";
const VDOM = (
  <div>
    <h2 id={mainID} className="title">
      <span style={{ color: "white", fontSize: "20px" }}>{mainData}</span>
    </h2>
    <h3>Hello</h3>
    <input type="text" /> 
    <ayaya>12345</ayaya>
  </div>
);

我在最后加了一个<ayaya>标签。但是HTML里面哪有<ayaya>标签啊,这不就是我瞎编出来的一个标签嘛,但是我们来看一下效果:

image-20211212121447203

诶?展示也正常,而且标签也渲染出来了。哦,那看来jsx里面只要是写成标签形式,而且关闭了就可以支持。但是这样对吗?我们知道react是把jsx里的标签渲染成HTML的,但是我里面出来了一个HTML中根本不存在的标签,他往哪渲染啊?虽然展示出来了,但是也不能就代表是对的啊。我们看一下控制台就知道了。

image-20211212121836497

这不是很明显报错了嘛,跟我们说<ayaya>标签不被浏览器支持。然后还询问了我们是不是想要渲染组件?如果是想要渲染组件的话,<ayaya>标签的首字母应该大写。

这段内容是什么意思呢?我们前面也介绍了,react最终是要把jsx渲染成HTML的,接下来便要提及react渲染jsx的底层逻辑了,我们目前在jsx中所写的所有标签都是小写的,react在渲染jsx的时候,会检查各个标签,如果这个标签首字母小写,那么react就会默认认为这是个HTML标签来进行直接渲染,如果这个标签,首字母大写,react就会认为这是个react组件,便会来渲染这个组件。当然目前来说我们还没有学习到组件的相关内容,这里就想做一个了解,知道有这么一回事儿就行了,后面的课程我们再深入研究。

所以说,当我们在写jsx的时候,不要胡乱起标签,HTML中有哪些标签,我们就用哪些标签。

那么我们便可以得到一个结论:如果jsx中标签首字母小写,那么则将该标签渲染为HTML中同名标签,若无同名标签则会报错。如果jsx中标签首字母大写,那么react就去渲染对应的组件,若该组件没有定义,则报错。

总结

  • jsx是类似于XMLjs扩展语法
  • jsx的本质是React.createElement(compoment,props,...children)方法的语法糖。
  • jsx可以使用HTML标签,但是jsx表达式中的的标签不是HTML/XML标签
  • jsx内需要通过{}来对js表达式进行支持。
  • jsx任何标签中class属性的指定必须用className来指定
  • jsx内联样式必须使用style={{key: value}}的方式来写
  • jsx虚拟DOM只允许有一个根标签。
  • jsx虚拟DOM中的任何一个标签都必须闭合。
  • jsx中的标签在被渲染时会检查标签首字母
    • 如果jsx中标签首字母小写,那么则将该标签渲染为HTML中同名标签,若无同名标签则会报错。
    • 如果jsx中标签首字母大写,那么react就去渲染对应的组件,若该组件没有定义,则报错。

以上就是jsx的一些核心规则。

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/jsx_rule/