JSX 语法的本质目的是为了使用基于 xml 的方式表达组件的嵌套,保持和 HTML 一致的结构,语法上除了在描述组件上比较特别以外,其它和普通的 Javascript 没有区别。 并且最终所有的 JSX 都会编译为原生 Javascript。
JSX = JavaScript XML
JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。
特点
- 类XML语法:有固定的标签开启和闭合。这能让复杂的树更易于阅读,优于方法调用和对象字面量的形式。
- 增强JS语义:不是模板,模板与页面是分离的,是字符串,而JSX是JS语法本身,有更多的扩展
- 结构清晰
- 抽象程度高:屏蔽了手动的DOM操作,跨平台-JSX是独立于平台的语法,React在不同的平台提供解释器
- 代码模块化:MVC是纵向切分,React是横向切分,大项目由众多小项目组成
HTML组件 与 React组件
HTML组件和HTML中原生的组件一样,而React组件是自定义的组件
JSX 中约定以大小写字母开头来区分,组件一般以大写字母开头
//JSX中支持绝大部分HTML标签 <label className="lb" htmlfor="uName" style={{color:‘red‘; font-size:‘14px‘}}></label>
// 组件类 class MyComponent extends React.Component{ ?render(){ ???return <div>Customer Component:{this.props.name}</div> ?} }
React.render(<MyComponent name="propsText"/>, document.getElementById(‘d1‘))
|
由于 JSX 就是 JavaScript,一些标识符像 class
和 for
不建议作为 XML 属性名。作为替代,React DOM 使用 className
和 htmlFor
来做对应的属性。
JSX转换器
JSX 把类 XML 的语法转成纯粹 JavaScript,XML 元素、属性和子节点被转换成 React.createElement
的参数。
React.createElement(HTML标签名称/父组件,标签属性,子元素)
//JSX语法 <label className="xxx" htmlFor="input">content</label>
//转换后 React.createElement(‘label‘, {className: ‘xxx‘, htmlFor: ‘input‘}, ‘content‘)
|
命名空间式组件
如果一个组件拥有多个子组件,可以将子组件做为父组件的属性
// 命令空间式组件 class FormRoot extends React.Component{ render(){ return( <div> FromRoot {this.props.children} </div> ) } }
class Row extends React.Component{ render(){ return( <div className="box" style={{color:‘#3f3‘, height:‘auto‘}}> Form Row {this.props.children} </div> ) } } class Label extends React.Component{ render(){ return <div className="box" style={{color:‘#f90‘}}> Form Label </div> } } class Input extends React.Component{ render(){ return <div className="box" style={{color:‘red‘}}> Form Input </div> } }
FormRoot.Row = Row; FormRoot.Label = Label; FormRoot.Input = Input;
class APP extends React.Component{ render(){ return ( <div className="box" style={{height:‘auto‘}}> <FormRoot> <FormRoot.Row> <FormRoot.Label /> <FormRoot.Input /> </FormRoot.Row> </FormRoot> </div> ) } }
React.render(<APP />, document.getElementById(‘box1‘));
|
Javascript表达式
在JSX语法中,使用{}
标识内部是JS表达式
JSX是HTML和JavaScript混写的语法,当遇到<
,JSX就当HTML解析,遇到{
就当Javascript解析
render(){ return <Person name={window.isLoggedIn ? window.name : ‘‘} /> }
|
属性表达式
在使用 JS表达式 做为属性时,必须使用 {}
包含在内,不可使用 ""
render(){ return <div className={2 > 1 ? ‘class-a‘ : ‘class-b‘}>content</div> }
|
子表达式
组件嵌套中同样可以使用 JS表达式 来处理组件的显示逻辑
render(){ return <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container> }
|
注释作用于源码,对源码做说明,不会出现实在渲染后的DOM中
var content = ( ?<div className="box"> ???{/* 一般注释, 用 {} 包围 */} ???<span ?????/* 多 ????????行 ????????注释 */ ?????name={2>1 ? ‘2‘ : ‘1‘} // 行尾注释 ???>{2>1 ? ‘2‘ : ‘1‘}</span> ?</div> );
React.render(content, document.getElementById(‘box1‘));
|
延展属性(Spread Attributes)
组件的属性应当在组件初始化时指定,而不应在初始化以后指定,这样会导致 props 对象的修改不可预测, React 也不能帮助检查属性类型。
//better <Component foo={x} bar={y} />
//bad <Component /> Component.props.foo = x; Component.props.bar = y;
|
属性延展是将一个对象添加为组件的属性的语法糖
操作符 ...
是ES6中的延展语法(spread operator),可以将一个对象展开
var props = { foo: x, bar: y }; var component = <Component { ...props } foo={‘override‘}>;
// 等价于 var component = <Component foo={x} bar={y} />;
|
注意:后面相同的属性覆盖掉前面的属性
JSX陷阱
style属性
style属性是用两个 {
包含的,最外层的 {
表示内部是一个JS表达式,里面的 {
表示是一个JS对象字面量
render(){ return ( <div style={{color:‘red‘}}> ???xxxxx </div> )
}
|
HTML转义
React 默认会转义所有字符串,为了防止各种 XSS 攻击。
可使用 __html
进行转义
var content=‘<strong>content</strong>‘;
React.render( ???<div>{content}</div>, ???document.body ); //页面直接输出: <strong>content</strong>
var content=‘<strong>content</strong>‘; ???
React.render( ???<div dangerouslySetInnerHTML={{__html: content}}></div>, ???document.body );
//输出加粗后的: content
|
标签闭合
在JSX中,无论是单标签还是成对的双标签,必有闭合符,不然会报错
render(){ return( <div> <img src="xxx.jpg" /> <button>确认<button/> </div> ) }
|
根节点
自定义组件在render()
函数中返回的组件内容,必须有一个根节点包含起来
// bad function render() { ??return (<p> .... </p> ?????????<p> .... </p>) } // good function render() { ??return (<p> .... </p>) }
function render() { ??return ( ??<div> ??<p> .... </p> ??<p> .... </p> ??</div> ??) }
|
循环遍历
通过循环遍历出生成的组件集合,在循环时一定要加上key
值
render(){ return ( <p> ?????{arr.map(function(it,i) { ???????return <span key={i}> {it} </span> ?????})} ?????</p> ) }
|
IF-ELSE
在JSX中是不可以直接在{}
中加入if-else
的
- 使用 三元操作符 来替代
if-else
,或者将复杂的操作在JSX外面使用JS去处理 - 使用闭包自执行函数
//错误的写法 // var App = ( // <div> // { // if(2>1){ // <p>SUCCESS</p> // }else{ // <p>FAILURE</p> // } // } // </div> // );
var App = ( <div className="box"> { 2>1 ? <p>SUCCESS</p> : <p>FAILURE</p> } </div> );
React.render(App, document.getElementById(‘box1‘))
// 或者 // 将逻辑抽离到JS中执行 var loginButton; if (loggedIn) { ?loginButton = <LogoutButton />; } else { ?loginButton = <LoginButton />; }
return ( ?<nav> ???<Home /> ???{loginButton} ?</nav> );
// 或者 // 使用闭包自执行函数 var App = ( <div className="box"> { (()=>{ if(2>1){ return <p>SUCCESS</p> }else{ return <p>FAILURE</p> } })() } </div> );
|
Show-Hide
class App extends React.Component{ constructor(){ super() this.state={ showHide: true } } render(){ return ( <div className="box" style={{heigth:‘auto‘}}> <div className={this.props.showHide?"":"hide"}>通过Props可以初始化这段文字的显示隐藏</div> <div className={this.state.showHide?"":"hide"}>通过State可以改变这段文字的显示隐藏</div> <input type="button" value={this.state.showHide ? ‘隐藏‘:‘显示‘} onClick={()=>{ this.setState({showHide : !this.state.showHide}) }} /> </div> ) } }
React.render(<App showHide={true} />, document.getElementById(‘box1‘))
|
Switch-Case
return ( ?<section> ???<h1>Color</h1> ???<h3>Name</h3> ???<p>{this.state.color || "white"}</p> ???<h3>Hex</h3> ???<p> ?????{(() => { ???????switch (this.state.color) { ?????????case "red": ??return "#FF0000"; ?????????case "green": return "#00FF00"; ?????????case "blue": ?return "#0000FF"; ?????????default: ?????return "#FFFFFF"; ???????} ?????})()} ???</p> ?</section> );
|
Loop:循环
var rows = []; for (var i=0; i < numrows; i++) { ???rows.push(<ObjectRow key={i}/>); }
render(){ return (<tbody>{rows}</tbody>); }
|
相关示例