查看原文
其他

[React启蒙系列]使用JSX

2016-09-15 zhangwang 前端圈

岩石教育-张旺投稿


在前一章我们学习了如何使用纯ES5方法创建React nodes,本章我们用大名鼎鼎的JSX来做类似的事情。前一章使得我们明确了理解了React nodes,JSX使得React nodes更加容易创建。

JSX是什么

JSX是JavaScript的语法拓展,其形式类似于XML/HTML,且需要经类似于Babel这样的预处理器处理后才能顺利被执行。 我们使用JSX构建了一个<ul>,如下:

var nav = (
 <ul id="nav">
   <li>
     <a href="#">Home</a>
   </li>
   <li>
     <a href="#">About</a>
   </li>
   <li>
     <a href="#">Clients</a>
   </li>
   <li>
     <a href="#">Contact Us</a>
   </li>
 </ul>
)
;

进Babel转义之后,浏览器中运行的代码如下:

var nav = React.createElement(
  "ul",
  { id: "nav" },
  React.createElement(
     "li",
     null,
     React.createElement(
        "a",
        { href: "#" },
        "Home"
     )
  ),
  React.createElement(
     "li",
     null,
     React.createElement(
        "a",
        { href: "#" },
        "About"
     )
  ),
  React.createElement(
     "li",
     null,
     React.createElement(
        "a",
        { href: "#" },
        "Clients"
     )
  ),
  React.createElement(
     "li",
     null,
     React.createElement(
        "a",
        { href: "#" },
        "Contact Us"
     )
  )
);

经过前面的学习,Babel转换之后的代码也很容易理解,但是可以看出,使用JSX,我们的代码简洁许多。

传统的前端学习一直倡导,JS,HTML,CSS分离,所以JSX这种写法有时候会有所争议,不过你依旧可以选择自己认为最好的方式来写React,不过就我看来使用JSX确实更加简单和直观。React团队也认为JSX更加有利于构建大型的项目。


本节笔记

1、不要把JSX当做一种模板语言,它其实是一种JS的语法拓展,并且需要编译后才能得到正确执行。

2、Babel是React团队选择的转换ES*和JSX语句为ES语句的工具,可以通过其官网或BabelHandBook了解更多相关知识。

3、使用JSX的好处表现在以下四个方面:

直观且容易理解;

用类HTML的树形结构在JavaScript中写HTML,避免了模板方法的学习和使用,可以方便的构建树形UI组件;

使用JSX可以避免书写出错;

对CSS友好,可以很方面的使用行内样式。

4、通过JSX Gotchas了解更多知识。

5、JSX是独立于React的存在,不过已经被ECMAScript列入创建类XML拓展的草案。

6、JSX中必须有/如不能只写<for-bar>而可以写<foo-bar />。

使用JSX 创建React nodes

通过前面的学习,你肯定知道如何使用React.createElement()方法创建React节点了。我们用一个例子来回顾这种方法:

//React node, which represents an actual HTML DOM node
var HTMLLi = React.createElement('li', {className:'bar'}, 'foo');
//React node, which represents a custom HTML DOM node
var HTMLCustom = React.createElement('foo-bar', {className:'bar'}, 'foo');

而如果我们使用Babel,创建一样的React节点的方法如下(假设你已经配置好了Babel):

//React node, which represents an actual HTML DOM node
var HTMLLi = <li className="bar">foo</li>;
//React node, which represents a custom HTML DOM node
var HTMLCustom = <foo-bar className="bar" >foo</foo-bar>;

JSX是在JavaScript中使用的,通过Babel,其最终还是转换为了上述之间创建React nodes 的语句。

Babel:

//React node, which represents an actual HTML DOM node
var HTMLLi = <li className="bar">foo</li>;
//React node, which represents a custom HTML DOM node
var HTMLCustom = <foo-bar className="bar" >foo</foo-bar>;
ReactDOM.render(HTMLLi, document.getElementById('app1'));
ReactDOM.render(HTMLCustom, document.getElementById('app2'));

HTML:

<div id="app1"></div>
<div id="app2"></div>

上述JSFiddle中的代码执行后HTML的结构如下:

<body>
 <div id="app1">
   <li class="bar" data-reactid=".0">foo</li>
 </div>
 <div id="app2">
   <foo-bar class="bar" data-reactid=".1">foo</foo-bar>
 </div>
</body>

是不是感觉使用JSX和直接使用HTML一样简单。


本节笔记

1、JSX支持类似XML的自闭和,所以如果没有子元素,你可以使用自闭和<Component/>;

2、和直接使用React nodes一样,使用JSX时如果通过props传入了不存在于真实HTML的属性,该属性不会被真的渲染,但是如果传给的是自定义元素,则会被渲染;

3、JSX中class写作className,for写作htmlFor,style写作驼峰式;

4、React支持以下HTML属性:

accept acceptCharset accessKey
action allowFullScreen
allowTransparency alt async
autoComplete autoFocus autoPlay
capture cellPadding cellSpacing
challenge charSet checked
classID className colSpan cols
content contentEditable
contextMenu controls coords
crossOrigin data dateTime
default defer dir disabled
download draggable encType form
formAction formEncType
formMethod formNoValidate
formTarget frameBorder headers
height hidden high href hrefLang
htmlFor httpEquiv icon id
inputMode integrity is keyParams
keyType kind label lang list
loop low manifest marginHeight
marginWidth max maxLength media
mediaGroup method min minLength
multiple muted name noValidate
nonce open optimum pattern
placeholder poster preload
radioGroup readOnly rel required
reversed role rowSpan rows
sandbox scope scoped scrolling
seamless selected shape size
sizes span spellCheck src srcDoc
srcLang srcSet start step style
summary tabIndex target title
type useMap value width wmode
wrap

在DOM中渲染JSX

JSX只是JS语法的拓展,用以更加方便的创建React nodes,其渲染到DOM的方法与前章类似,只是多了使用babel转换的过程,依旧使用ReactDOM.render()方法看以下例子就知道了:

Babel:

//React node, which represents an actual HTML DOM node
var HTMLLi = <li className="bar">foo</li>;
//React node, which represents a custom HTML DOM node
var HTMLCustom = <foo-bar className="bar" >foo</foo-bar>;
//Render the HTMLLI React node to <div id="app1"></div>
ReactDOM.render(HTMLLi, document.getElementById('app1'));
//Render the HTMLCustom React node to <div id="app2"></div>
ReactDOM.render(HTMLCustom, document.getElementById('app2'));

HTML:

<div id="app1"></div>
<div id="app2"></div>

渲染结果如下:

<body>
 <div id="app1">
   <li class="bar" data-reactid=".0">
     foo
   </li>
 </div>
 <div id="app2">
   <foo-bar classname="bar" children="foo" data-reactid=".1">
     foo
   </foo-bar>
 </div>
</body>

本节要点和前章一致,在此不再赘述。

在JSX中使用JS表达式

想在JSX代码中写可以运行的JS代码其实也很简单,只需要简单的用{}大括号围起即可,其中代码可被直接执行。 看以下例子:

Babel:

var label = '2 + 2';
var inputType = 'input';
//Note how I use JavaScript expressions/values via {} intermingled among JSX
var reactNode = <label>{label} = <input type={inputType} value={2+2} /></label>;
ReactDOM.render(reactNode, document.getElementById('app1'));

HTML:

<div id="app1"></div>

value中的2+2可以被直接执行,其经Babel转换后的代码如下:

var label = '2 + 2';
var inputType = 'input';
var reactNode = React.createElement(
  'label',
  null,
  label,
  ' = ',
  React.createElement('input',{type:inputType,value:2+2})
);
ReactDOM.render(reactNode, document.getElementById('app1'));

经浏览器的JavaScript引擎渲染后,结果如下:

<div id="app1">
 <label data-reactid=".0">
   <span data-reactid=".0.0">
     2 + 2
   </span>
   <span data-reactid=".0.1">
     =
   </span>
   <input type="input" value="4" data-reactid=".0.2">
 </label>
</div>

在JSX中添加注释

要避免在React子节点处添加注释,也不要在{}中添加注释,防止React把其传递给到真实的JavaScript代码中。

var reactNode = <div /*comment*/>{/* use {'{}'} here to comment*/}</div>;

上述代码被在HTML中的转换结果如下:

<div data-reactid=".0">
   <span data-reactid=".0.0">
     /* use
   </span>
   <span data-reactid=".0.1">
     {}
   </span>
   <span data-reactid=".0.2">
     here to comment*/
   </span>
</div>

在JSX中使用行内样式

通过给style属性赋值就可以使用行内样式了,在JSX中使用行内样式非常方便,看如下代码:

Babel:

var styles = {
   color:'red',
   backgroundColor:'black',
   fontWeight:'bold'
};
var reactNode = <div style={styles}>test</div>;
ReactDOM.render(reactNode, document.getElementById('app1'));

HTML:

<div id="app1"></div>

值得注意的是CSS属性都采用的是驼峰式写法,JavaScript中的变量名并不允许出现连字符-

上述代码在HTML的表现结果如下:

<div style="color:red;background-color:black;font-weight:bold;" data-reactid=".0">
   test
</div>

本节比较

1、CSS属性名中的连字符后面的第一个字母应该大写;

2、除了下属属性外,React中的数值的默认单位为px:

columnCount fillOpacity flex
flexGrow flexShrink fontWeight
lineClamp lineHeightopacity
order orphans strokeOpacity
widows zIndex zoom

在JSX中使用props

在前面的章节的学习中,你也知道了props的作用,下面的代码展示如何在JSX中使用props,及不同的props的作用:

var styles = {backgroundColor:'red'};
var tested = true;
var text = 'text';

var reactNodeLi =
   <li id=""
       data-test={tested?'test':'false'}
       className="blue"
       aria-test="test"
       style={styles}
       foo="bar">
       {text}
   </li>;


ReactDOM.render(reactNodeLi, document.getElementById('app1'));

上述代码经Babel装换后如下:

var reactNodeLi = React.createElement(
   'li',    { id: '',
       'data-test': tested ? 'test' : 'false',        className: 'blue',
       'aria-test': 'test',        style: styles,        foo: 'bar' },    text );

渲染结果如下:

<div id="app1">
   <li id="true"        data-test="test"        class="blue"        aria-test="test"        style="background-color:red;"        data-reactid=".0">            text
   </li>
</div>

有以下值得注意的地方:

1、props中的空白值结果为true;

2、在真实HTML元素中不存在的属性,渲染的DOM后也不会存在。


本节笔记

1、React中值为空白的props,渲染后其值为true (比如说id=""渲染后为id="true",test渲染后为test="true" );

2、props中如果同一属性出现两次,后者的值将生效;

3、props中被传入的标准React 元素属性(HTML中真实存在的元素的属性),渲染后依旧是该元素的对应属性值,非标准元素的属性将不会被渲染,如果传入的是一个自定义元素,那么其所有的属性都将被渲染如<x-my-component custom-attribute="foo" />;

4、React中class属性写作className,for写作htmlFor,style属性为写作驼峰式;

5、HTML表单元素 (<input>、<textarea></textarea>等),当其由React创建时,其支持与交互有关的属性value、checked、selected等;

6、key、ref、dangerouslySetInnderHtml属性不存在于真实DOM中,它们在React中有独特的作用;

7、React中所有的属性都被写作驼峰式(如accept-charset写做acceptCharset);

8、以下是React支持的一些属性:

accept acceptCharset accessKey
action allowFullScreen
allowTransparency alt async
autoComplete autoFocus autoPlay
capture cellPadding cellSpacing
challenge charSet checked
classID className colSpan cols
content contentEditable
contextMenu controls coords
crossOrigin data dateTime
default defer dir disabled
download draggable encType
form formAction formEncType
formMethod formNoValidate
formTarget frameBorder headers
height hidden high href
hrefLang htmlFor httpEquiv
icon id inputMode integrity is
keyParams keyType kind label
lang list loop low manifest
marginHeight marginWidth max
maxLength media mediaGroup
method min minLength multiple
muted name noValidate nonce
open optimum pattern placeholder
poster preload radioGroup
readOnly rel required reversed
role rowSpan rows sandbox scope
scoped scrolling seamless
selected shape size sizes span
spellCheck src srcDoc srcLang
srcSet start step style summary
tabIndex target title type
useMap value width wmode wrap

在JSX中使用事件

在JSX中使用添加事件非常简单,看如下代码 先回顾前一章的代码 :

Babel:

var mouseOverHandler = function mouseOverHandler() {
 console.log('you moused over'); };
var clickhandler = function clickhandler() {
 console.log('you clicked'); };
var reactNode = React.createElement(
 'div',  { onClick: clickhandler, onMouseOver: mouseOverHandler },
 'click or mouse over'); ReactDOM.render(reactNode, document.getElementById('app'));

利用JSX达到相同的效果的代码如下 :

Babel:

var mouseOverHandler = function mouseOverHandler() {
   console.log('you moused over'); };
var clickHandler = function clickhandler() {
   console.log('you clicked'); };
var reactNode = <div onClick={clickHandler} onMouseOver={mouseOverHandler} >click or mouse over</div>;

ReactDOM.render(reactNode, document.getElementById('app'));

在此我们使用{}给一个节点绑定一个事件,创建方法类似于DOM 0,不过不用担心React 并非针对DOM绑定了事件。

React支持的事件可见下表:http://www.reactenlightenment.com/react-jsx/5.8.html


本节笔记

1、React中的各事件已经规范化,你可以放心的跨浏览器使用;

2、React事件默认在事件冒泡阶段(bubblling)触发,如果想在事件捕获阶段触发需要在事件名后加上Capture(如onClick变为onClickCapture);

3、如果你想获知浏览器事件的详情,你可以通过在回调函数中查看SyntheticEvent对象中的nativeEvent值;

4、React实际上并未直接为React nodes添加事件,它使用了event delegation事件委托机制;

5、想要阻止事件冒泡,需要手动调用e.stopPropagation() 或e.preventDefault(),不要直接使用returning false;

6、React其实并没有支持所有的JS事件,不过它还提供额外的生命周期函数以供使用React lifecycle methods。



【React启蒙系列文章】

一、[React启蒙系列] 初探React

二、[React启蒙系列] 学习React前需要理解的名词

三、[React启蒙系列] React和Babel的基本使用

四、[React启蒙系列]React节点


【您可能感兴趣的文章】

一、手把手教你用react

二、React入门及资源指引

三、利用ESLint检查代码质量

四、构建一个安全的 JavaScript 沙箱

五、入门Webpack,看这篇就够了

六、第三届CSS大会广州找场地啦~~求介绍~~

七、Web Components 是个什么样的东西

八、JavaScript 被忽视的细节



前端圈--打造专业的前端技术会议

为web前端开发者提供技术分享和交流的平台

打造一个良好的前端圈生态,推动web标准化的发展

官网:http://fequan.com

微博:fequancom | QQ群:41378087



长按二维码关注我们

投稿:content@fequan.com

赞助合作:apply@fequan.com

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存