前文我们了解了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
定义的一种类似于XML
的 JavaScript
扩展语法 即: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"));
这次我们再看:
这样便满足了我们的需求。
从而我们得出一个结论就是: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> );
那我们来看一下效果。
诶?有效果,既然有效果为啥我还在注释里标注了是错误写法呢?那我们打开控制台看一下,有一个报错信息。
这个报错告诉我们class
属性在当前DOM
中不被允许,问我们想要用的是不是className
属性。所以我们不妨大胆地臆测一下。我们是不是这么写就对了呢?
// 猜想 let mainID = "title"; let mainData = "Hello react"; const VDOM = ( <h2 id={mainID} className="title"> <span>{mainData}</span> </h2> );
再看一下结果:
这次就没有报错了,而且样式效果也出来了。
所以我们又得出一个结论就是: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
属性嘛,直接写不就好了嘛。那我们来试一试。
啥都没显示,而且还出来了这么多的报错信息。但是这一堆信息是怎么说的呢?第一条信息告诉我们,<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> );
然后再回头看一下效果:
诶,这样就成功了。
但是为什么啊?我们来分析一下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
会有很直观的报错提醒:
而且报错信息里也说得很清楚,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> );
我们来看一下效果:
这样我们就可以成功实现我们的需求了。
所以我们从以上内容有得出一个结论:虚拟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> );
依然还是给我报错了啊。跟我说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>
标签啊,这不就是我瞎编出来的一个标签嘛,但是我们来看一下效果:
诶?展示也正常,而且标签也渲染出来了。哦,那看来jsx
里面只要是写成标签形式,而且关闭了就可以支持。但是这样对吗?我们知道react
是把jsx
里的标签渲染成HTML
的,但是我里面出来了一个HTML
中根本不存在的标签,他往哪渲染啊?虽然展示出来了,但是也不能就代表是对的啊。我们看一下控制台就知道了。
这不是很明显报错了嘛,跟我们说<ayaya>
标签不被浏览器支持。然后还询问了我们是不是想要渲染组件?如果是想要渲染组件的话,<ayaya>
标签的首字母应该大写。
这段内容是什么意思呢?我们前面也介绍了,react
最终是要把jsx
渲染成HTML
的,接下来便要提及react
渲染jsx
的底层逻辑了,我们目前在jsx
中所写的所有标签都是小写的,react
在渲染jsx
的时候,会检查各个标签,如果这个标签首字母小写,那么react
就会默认认为这是个HTML
标签来进行直接渲染,如果这个标签,首字母大写,react
就会认为这是个react
组件,便会来渲染这个组件。当然目前来说我们还没有学习到组件的相关内容,这里就想做一个了解,知道有这么一回事儿就行了,后面的课程我们再深入研究。
所以说,当我们在写jsx
的时候,不要胡乱起标签,HTML
中有哪些标签,我们就用哪些标签。
那么我们便可以得到一个结论:如果jsx
中标签首字母小写,那么则将该标签渲染为HTML
中同名标签,若无同名标签则会报错。如果jsx
中标签首字母大写,那么react
就去渲染对应的组件,若该组件没有定义,则报错。
总结
jsx
是类似于XML
的js
扩展语法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/