企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
&emsp;&emsp;JSX既不是字符串,也不是HTML,而是一种类似XML,用于描述用户界面的JavaScript扩展语法,如下代码所示。在使用JSX时,为了避免自动插入分号时出现问题,推荐在其最外层用圆括号包裹,并且必须用一个元素包裹(例如下面的元素)其它元素或文本,所有的元素还必须得闭合。 ~~~html (<div> <input type="text" text={getName()} /> <button className="btn">搜索</button> </div>) ~~~ &emsp;&emsp;JSX为视图和数据架起了一座沟通的桥梁,它看起来与模板语言类似,但没有创造新的模板语法,因为JSX最终会被编译成普通的JavaScript对象,所以能够直接使用JavaScript语法。 ## 一、元素 &emsp;&emsp;JSX中的元素称为React元素,分为两种类型:DOM元素和组件元素,前者对应原生的HTML元素,标签的首字母要小写;后者对应自定义元素,标签的首字母要大写,如下所示。 ~~~html <button>提交</button>; //DOM元素 <Btn>自定义按钮</Btn>; //组件元素 ~~~ **1)React.createElement()** &emsp;&emsp;无论是DOM元素还是组件元素,最终都会通过Babel编译器将它们转换成React.createElement()方法的调用,例如下面的元素。 ~~~js <button className="btn">搜索</button> //编译成 React.createElement(button, { className: "btn" }, "搜索"); ~~~ &emsp;&emsp;React.createElement()能接收3个参数(如下所示),其中type是元素类型,也就是它的名称;props是一个由元素属性组成的对象;children是它的子元素(即内容),可以是文本也可以是其它元素。 ~~~js React.createElement(type, [props], [...children]) ~~~ &emsp;&emsp;方法的返回值是一个元素对象,简化过的对象如下所示。 ~~~json { type: "button", props: { className: "btn", children: "搜索" } } ~~~ &emsp;&emsp;为了避免在多人协作时出现相同名称的元素,可以为元素添加命名空间,例如调用UI模块中的Btn元素,可以像下面这么写。 ~~~js const UI = { Btn: function(props) { return <button className={props.className}>{props.children}</button>; } } <UI.Btn className="btn">搜索</UI.Btn> ~~~ **2)注释** &emsp;&emsp;JSX中的注释需要像下面这样,用一对花括号、斜杠和星号包裹。 ~~~js {/* 表单中的提交按钮 */} <button>提交</button> ~~~ **3)表达式** &emsp;&emsp;在JSX的任意位置都能插入表达式,但必须用花括号包裹住才能有效,例如像下面这样调用getName()函数。注意,在JSX中不能插入语句。 ~~~js function getName() { return "strick"; } <div>{getName()}</div> ~~~ &emsp;&emsp;由于JSX本身就是一种表达式,因此它可以作为函数的参数、返回值或变量的值,如下所示。 ~~~js if (true) { let fragment = <div>{getName()}</div>; } ~~~ &emsp;&emsp;在JSX中传入的值都会自动被HTML转义,这样可以防止XSS攻击,例如输入“\<p>\</p>”,输出“\&lt;p\&gt;\&lt;/p\&gt;”,如下所示。 ~~~js //&lt;p&gt;&lt;/p&gt; <div>{"<p></p>"}</div> ~~~ &emsp;&emsp;如果要输出不转义的值,那么可以用React提供的dangerouslySetInnerHTML属性,如下代码所示。它的值是一个包含\_\_html属性的对象,其作用相当于调用DOM元素的innerHTML属性。 ~~~html <div dangerouslySetInnerHTML={{__html: "<p></p>"}}></div> ~~~ **4)内容** &emsp;&emsp;当元素的内容是字符串时,JSX会移除字符串中的空行,其内部的换行会被替换成一个空格,下面的两个元素是等价的。 ~~~html <p>freedom strick</p> <p> freedom strick </p> ~~~ &emsp;&emsp;当元素的内容是false、null、undefined或true时,它们都不会被渲染到DOM结构中,因此下面的五个元素是等价的。 ~~~html <p></p> <p>{false}</p> <p>{null}</p> <p>{undefined}</p> <p>{true}</p> ~~~ **5)渲染** &emsp;&emsp;如果要将React元素渲染到页面的DOM结构中,可以调用ReactDOM.render()方法,此方法接收3个参数,如下所示。 ~~~js ReactDOM.render(element, container[, callback]) ~~~ &emsp;&emsp;element是要渲染的元素;container是页面中的一个节点,在此处起到容器的作用,element会被渲染到container中;callback是可选的回调函数,会在组件被渲染或更新之后触发。此方法的使用可参考下面的示例。 ~~~html <div id="container">freedom</div> <script type="text/babel"> ReactDOM.render( <p>strick</p>, document.getElementById("container") ); </script> ~~~ &emsp;&emsp;当第一次调用ReactDOM.render()方法时,容器内部的元素会被全部替换掉,也就是执行上面的代码得到的结果如下所示,原先的字符串“freedom”被替换成了元素。 ~~~html <div id="container"> <p>strick</p> </div> ~~~ ## 二、属性 &emsp;&emsp;React对元素属性进行了一次封装,不仅规范了属性的命名,还完善了浏览器的兼容性。在JSX中,DOM元素的属性对应标准的DOM属性和特性;而组件元素的属性都是无对应关系的自定义属性。除了以“data-”和“aria-”为前缀的元素属性要用小写命名之外,其余的都得遵循小驼峰命名法,例如maxlength变成maxLength、onclick变成onClick等。还有两个比较特殊的属性:class和for,由于它们是JavaScript的关键字,因此需要变成className和htmlFor后才能使用。 **1)默认值** &emsp;&emsp;属性的默认值是true,下面的两个元素是等价的,页面上的显示如图1所示。 ~~~html <input type="text" value /> <input type="text" value={true} /> ~~~ :-: ![](https://box.kancloud.cn/5c5af1ac515467a782c520e3a51d939a_341x121.png) :-: 图 1 带默认值的文本框 &emsp;&emsp;在标准的DOM中,诸如checked、disabled等布尔属性,它们的值要么为空要么为对应的关键字,例如“checked”、“disabled”;而JSX中的布尔属性,它们的值只能是true或false。 **2)字符串和表达式** &emsp;&emsp;当属性的值是字符串时,其值需要用双引号包裹;当属性的值是表达式时,其值需要用花括号包裹,如下所示。 ~~~html <input type="text" value="3" /> <input type="text" value={1 + 2} /> ~~~ **3)扩展属性** &emsp;&emsp;如果存在一个由元素属性组成的属性对象,那么就能利用ES6新增的扩展运算符,把属性对象展开并传递给元素,如下所示。 ~~~js var props = { type: "text", value: "1" }; <input {...props} /> //相当于 <input type="text" value="1" /> ~~~ &emsp;&emsp;相比直接在元素上设置属性,这种方式操作起来更加灵活。 ## 三、虚拟DOM &emsp;&emsp;HTML文档能被抽象成一棵由多种类型的节点构成的DOM树,而每次对DOM节点执行增删改查等操作,往往会触发非常消耗性能的重绘和重排。为了解决这个性能瓶颈,React引入了虚拟DOM。虚拟DOM(Virtual DOM)是构建在真实DOM之上的一层抽象,它将DOM元素映射成内存中的JavaScript对象(即通过React.createElement()得到的React元素),形成一棵JavaScript对象树。 &emsp;&emsp;在React中,将虚拟DOM转换成真实DOM的过程叫做调和(Reconciliation),而diff算法是保证调和高效的关键,因为diff算法会找出新旧虚拟DOM之间的差异部分,随后只更新真实DOM中需要变化的节点,而不是将整棵DOM树重新渲染一遍。经过虚拟DOM的隔离,开发人员已经不用再直接与页面上的真实DOM打交道了,如图2所示。 :-: ![](https://box.kancloud.cn/9535161bb5b2e47fb1336d620885e99c_1234x318.png =600x) :-: 图 2 新的开发模式 &emsp;&emsp;虚拟DOM还有一大亮点,那就是将它与其他渲染器配合能够集成到指定的终端,即将React元素映射成对应的原生控件,前文所描述的是用react-dom在Web端渲染,还可以使用react-native在手机端(Android或iOS)渲染。 ***** > 原文出处: [博客园-React躬行记](https://www.cnblogs.com/strick/category/1455720.html) [知乎专栏-React躬行记](https://zhuanlan.zhihu.com/pwreact) 已建立一个微信前端交流群,如要进群,请先加微信号freedom20180706或扫描下面的二维码,请求中需注明“看云加群”,在通过请求后就会把你拉进来。还搜集整理了一套[面试资料](https://github.com/pwstrick/daily),欢迎浏览。 ![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200) 推荐一款前端监控脚本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不仅能监控前端的错误、通信、打印等行为,还能计算各类性能参数,包括 FMP、LCP、FP 等。