一、JSX简介

JSX 是 JavaScript 语法的扩展,是 Facebook 团队提出的一个语法方案,可以在 JavaScript 的代码直接中使用 HTML 标签来编写 JavaScript 对象,这种语法方案需要通过 JSXTransformer 来进行编译转换成真实可用的 JavaScript 代码。

React 是基于组件的开发思想,React 认为一个组件可以是一个完全独立的没有任何其他依赖的模块文件。一个组件中可以有自己的样式(Inline Style)和结构(JSX编写的HTML)。

二、语法规则

允许 HTML 与 JavaScript 的混写:HTML 语言直接写在 JavaScript 语言之中,不加任何引号,遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。

使用JSX来创建一个HTML标签,首字母小写:

 var link = <a href="xxx">Hello World!</a>

使用JSX来创建一个React组件:

var HelloWorld = <HelloWorld foo="bar"></HelloWorld>

备注

  • React 的 JSX 里约定分别使用首字母大、小写来区分React组件和 HTML 标签。

  • 由于JSX 是直接将 HTML 写在 JavaScript 代码中,如果HTML 中的属性是 JavaScript 的关键字,则必须进行转换,转换规则和在 JavaScript 中使用 DOM 的 property 一样。例如 class 和 for 使用 className 和 htmlFor 来代替。

  • JSX 标签的标签都需要有完整的结束符号,否则编译会报错。

三、基本语法

1、变量

JSX中可以通过 {xxx} 来插入一个JavaScript变量:

var message = 'Hello World!';
<span>{message}</span>

2、根节点

每一段JSX代码都只能有一个根节点,否则编译不通过,尤其是多行语句的时候。

var btnBox = (
	<div>
		<button>Click me</button>
		<p>Hello World!</p>
	</div>
);

3、表达式

JSX中支持三元表达式:

var person = <Person name={window.isLoggedIn ? window.username : ''}/>
var content = <Container>{window.isLoggedIn ? <Nav/> : <Login/>}</Container>

4、流程控制

  • if-else

在JSX中不能直接在{}中使用if-else,可以使用三元表达式代替:

<div>{locale === 'zh-CN' ? '您好!' : 'Hello'}</div>

三元表达式往往并不能满足需求,React建议在JS代码中使用if-else,如下:

var button;
if(window.isLoggedIn){
	button = <LogoutButton/>
}else{
	button = <LoginButton/>
}
reutrn (
	<nav>
		<Home/>
		{button}
	</nav>
);
  • switch-case
<p>
	{(()=>{
		switch(this.state.color){
			case "red":
				return "#f00";
			case "green":
				return "#0f0";
			case "blue":
				return "#00f";
			default: 
				return "#fff";
		}
	})()}
</p>
例子中使用了es6的箭头函数语法。
  • for
var toolbar = [];
for(var i = 0; i < buttons.length; i++){
	toolbar.push(<LinkButton key={i}/>);
}
return (
	<div id="toolbar">{toolbar}</div>
);

5、JSX中使用样式

在JSX中使用样式和HTML中很类似,通过style属性来定义,不同的是,属性值不能是字符串而必须为对象。

在JSX中可以使用所有的的样式,属性名的转换规范就是将其写成驼峰写法,例如background-color变为backgroundColor, font-size变为fontSize,这和标准的JavaScript操作DOM样式的API是一致的。

<div style={ {color:"#000",fontSize:"14px"} }></div>
//或先将样式定义为变量再使用
var style = {color:"#000",fontSize:"14px"};
return (
	<div style={style}>HelloWorld!</div>
);

6、JSX中绑定事件

JSX 中的事件绑定和原生HTML定义事件基本一致,唯一的区别是JSX采用驼峰写法来描述事件名称,大括号中仍然是标准的JavaScript表达式,返回一个事件处理函数。

<button onClick={this.handleClick}>Click me</button>

React并不会真正的绑定事件到每一个具体的元素上,而是采用事件代理的模式:在根节点document上为每种事件添加唯一的Listener,然后通过事件的target找到真实的触发元素。这样从触发元素到顶层节点之间的所有节点如果有绑定这个事件,React都会触发对应的事件处理函数。这就是所谓的React模拟事件系统。尽管整个事件系统由React管理,但是其API和使用方法与原生事件一致。

7、展开操作符

在JSX中可以使用类似于ES6的展开操作符...

var props = {foo: "x", bar: "y"};
var component = <Component {...props}/>;

展开操作符也可以和其它属性一起使用:

var props = {foo: "default"};
var component = <Component {...props} foo="override"/>;//后面的属性值会覆盖掉前面的
console.log(component.props.foo);//override

8、HTML转义

由于为了防止各种 XSS 攻击, React 默认会转义所有字符串。如果想直接使用原始 HTML,可以使用dangerouslySetInnerHTML属性。如果不到万不得已,不建议这么做。

var htmlContent = '<a href="https://baidu.com">Baidu</a>';
var component = <span dangerouslySetInnerHTML={ { __html: htmlContent} } />;

9、自定义HTML属性

如果往原生 HTML 元素里传入 HTML 规范里不存在的属性,React 不会显示它们。如果需要使用自定义属性,要加 data- 前缀。
以 aria- 开头的 [网络无障碍] 属性可以正常使用。

<div data-custom-attribute="foo"/>
<div aria-hidden={true}/>

10、命名空间

JSX中还可以支持组件的命名空间,可以让组件的层次更清晰,更语义化。

var Form = React.createClass({
	render: function(){
		return <form className="myform">{this.props.children}</form>;
	}
});
Form.Row = React.createClass({
	render: function(){
		return (<div className="myrow">{this.props.children}</div>);
	}
});
Form.Label = React.createClass({
	render: function(){
		return <label htmlFor="message" className="mylabel">留言:</label>
	}
});
Form.Input = React.createClass({
	render: function(){
		return <input id="message" className="myinput" placeholder="请输入留言信息"/>;
	}
});
var App = (
	<Form>
		<Form.Row>
			<Form.Label />
			<Form.Input />
		</Form.Row>
	</Form>
);

11、JSX中特殊的false

false 在 JSX 中的不同位置有不同作用 。id={false}value={false} 都换转换成字符串 falsedisabled={false} 是设置 disabled 属性为 false<p>{false}</p> 表示该 p 标签没有子元素。

<div id={false}>
	<input type="text" name="name" value={false}/>
	<button disabled={false}>Click me</button>
	<p>false</p>
</div>

12、注释

JSX中的注释需要写在花括号中:

 return (
	<Nav>
		{/*comment*/}
		{/*
				comments
		*/}
		<Person name={window.isLoggedIn ? window.name : ''}/>
	</Nav>
);

四、JSX Transform

JSX 把类 XML 的语法转成原生 JavaScript,XML 元素、属性和子节点被转换成 React.createElement 的参数。

var Nav;
//输入(JSX)
var app = <Nav color="blue"/>
//输出(JS)
var app = React.createElement(Nav, {color:"blue"});

JSX中也支持使用XML语法定义子结点:

var Nav, Profile;
//输入(JSX)
var app = <Nav color="blue"><Profile>profile</Profile></Nav>;
//输出(JS)
var app = React.createElement(
	Nav,
	{color:"blue"},
	React.createElement(Profile, null, "profile");
);

浏览器中的JSX转换器是相当大的,并且会在客户端导致无谓的计算,这些计算是可以避免的。不要在生产环境直接使用JSX,应该使用 react-tools 等工具预编译JSX后再使用。

五、代码风格建议

为了代码有更好的可读性,无论是单行语句还是多行语句,都建议使用 () 来包裹 JSX 语句。在 JSX 中插入 JavaScript 语句的时候尽量不要嵌套太长的三目运算符,JSX 本身就是为了开发更简便和更好的维护性。