一、基础
1、JSX是什么
JSX是一种像下面这样的语法:
const element = <h1>Hello, world!</h1>;
它是一种JavaScript语法扩展,在React中可以方便地用来描述UI。
本质上,JSX为我们提供了创建React元素方法(React.createElement(component, props, ...children)
)的语法糖(syntactic sugar)。上面的代码实质上等价于:
var element = React.createElement(
"h1",
null,
"Hello, world!"
);
2、JSX代表JS对象
JSX本身也是一个表达式,在编译后,JSX表达式会变成普通的JavaScript对象。
你可以在if语句或for循环中使用JSX,你可以将它赋值给变量,你可以将它作为参数接收,你也可以在函数中返回JSX。
例如下面的代码:
1. function getGreeting(user) {
2. if (user) {
3. return <h1>Hello, {formatName(user)}!</h1>;
4. }
5. return <h1>Hello, Stranger.</h1>;
6. }
上面的代码在if语句中使用JSX,并将JSX作为函数返回值。实际上,这些JSX经过编译后都会变成JavaScript对象。
经过babel会变成下面的js代码:
function test(user) {
if (user) {
return React.createElement(
"h1",
null,
"Hello, ",
formatStr(user),
"!"
);
}
return React.createElement(
"h1",
null,
"Hello, Stranger."
);
}
3、在JSX中使用JavaScript表达式
在JSX中插入JavaScript表达式十分简单,直接在JSX中将JS表达式用大括号括起来即可。例如:
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
上面的代码中用到了函数调用表达式fromatName(user)。
在JavaScript中,表达式就是一个短语,Javascript解释器会将其计算出一个结果,常量就是最简单的一类表达式。常用的表达式有:
- 变量名;
- 函数定义表达式;
- 属性访问表达式;
- 函数调用表达式;
- 算数表达式;
- 关系表达式;
- 逻辑表达式;
需要注意的是,if语句以及for循环不是JavaScript表达式,不能直接作为表达式写在{}中,但可以先将其赋值给一个变量(变量是一个JavaScript表达式):
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
return <div>{props.number} is an {description} number</div>;
}
4、JSX属性值
你可以使用引号将字符串字面量指定为属性值:
const element = <div tabIndex="0"></div>;
注意这里的”0”是一个字符串字面量。
或者你可以将一个JavaScript表达式嵌在一个大括号中作为属性值:
const element = <img src={user.avatarUrl}></img>;
这里用到的是JavaScript属性访问表达式,上面的代码将编译为:
const element = React.createElement("img", { src: user.avatarUrl });
5、JSX的Children
首先JSX可以是一个不包含Children的empty tag。如:
const element = <img src={user.avatarUrl} />;
JSX也可以像HTML标签一样包含Children:
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
这种写法在生成React元素的时候给我们带来了很大的便利,而且能够更加直观地描述UI。不然我们需要像下面这样创建和上面代码等价的React元素:
const element = React.createElement(
"div",
null,
React.createElement(
"h1",
null,
"Hello!"
),
React.createElement(
"h2",
null,
"Good to see you here."
)
);
tip: React DOM结点使用骆驼拼写法给属性命名
例如:class在JSX中应写作className,tabindex应写作tabIndex。
另外关于JSX的children需要注意的是:
React自定义组件的chilren是不会像固有的HTML标签的子元素那样自动render的,我们看下面的例子:
class Test extends React.Component {
render() {
return (
<div>
Here is a list:
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
)
}
};
ReactDOM.render(
<Test />,
document.getElementById('test')
);
以上代码定义的组件中都是build-in组件,类似div、p、ul、li等。它们中的子元素会直接render出来,像下面这样:
但是如果你使用用户定义组件,比如:
class Test extends React.Component {
render() {
return (
<Em>
Here is a list:
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</Em>
)
}
};
class Em extends React.Component {
render() {
return (<div></div>);
}
}
ReactDOM.render(
<Test />,
document.getElementById('test')
);
并不能得到跟上面代码1一样的结果,我们得到的只是一个空的div标签:
如果你想得到和代码1一样的结果,需要显示地指定props.children,像下面这样:
1. class Test extends React.Component {
2. render() {
3. return (
4. <Em>
5. Here is a list:
6. <ul>
7. <li>Item 1</li>
8. <li>Item 2</li>
9. </ul>
10. </Em>
11. )
12. }
13. };
14.
15. class Em extends React.Component {
16. render() {
17. return (<div>{this.props.children}</div>);
18. }
19. }
20.
21. ReactDOM.render(
22. <Test />,
23. document.getElementById('test')
24. );
6、JSX可自动防范注入攻击
在JSX中嵌入接收到的内容是安全的,比如:
1. const danger = response.potentialDanger;
2.
3. cosnt ele = <h1>{title}</h1>
在默认情况下,React DOM会将所有嵌入JSX的值进行编码。这样可以有效避免xss攻击。
我们将以下代码编译后引入html:
1. class Test extends React.Component {
2. render() {
3. let v = "<script><\/script>";
4. return (
5. <div>
6. <h1>{v}</h1>
7. </div>
8. )
9. }
10. };
11.
12. ReactDOM.render(
13. <Test />,
14. document.getElementById('test')
15. );
得到结果是:
可以看到通过JSX插入的文本自动进行了HTML转义,所以这里插入的是一段文本,而不是<script>
标签。这有点类似于Js中的document.createTextNode("...")
(实际上我们可以利用document.createTextNode进行HTML转义)。
作为对比,换作使用DOM元素的innerHTML属性:
1. <!DOCTYPE html>
2. <html>
3. <head>
4. <meta charset="utf-8">
5. </head>
6. <body>
7. <div id="test"></div>
8. <script type="text/javascript">
9. document.getElementById("test").innerHTML="<h1><script><\/script><\/h1>";
10. </script>
11. </body>
12. </html>
得到结果如下:
注意文本的颜色,此时插入的是一个<script>
标签。
如果你很清楚自己在做什么,希望直接将字符串不经转义编码直接插入到HTML文档流,可以使用dangerouslySetInnerHTML
属性,这是一个React版的innerHTML,该属性接收一个key为__html的对象,修改代码如下:
1. class Test extends React.Component {
2. render() {
3. let v = {
4. __html: "<script><\/script>"
5. };
6. return (
7. <div>
8. <h1 dangerouslySetInnerHTML={v}/>
9. </div>
10. )
11. }
12. };
二、进阶
1、JSX中的props
指定JSX中的props有以下几种方式:
(1)使用JavaScript表达式
任何有效的JavaScript表达式都可以作为prop的值,使用的时候将该表达式放在一对大括号中即可:
1. <MyComponent foo={1 + 2 + 3 + 4} />
2.
3. <YourComponent clickTodo={(id) => this.props.handleClick(id)} />
(2)使用字符串字面量
字符串字面量可以作为prop值,下面的代码是等价的:
1. <MyComponent message="hello world" />
2.
3. <MyComponent message={'hello world'} />
(3)使用扩展运算符
如果你想将一个prop对象传入JSX,你可以使用扩展运算符...
直接将整个prop对象传入。下面的2个组件是等价的:
1. function App1() {
2. return <Greeting firstName="Ben" lastName="Hector" />;
3. }
4.
5. function App2() {
6. const props = {firstName: 'Ben', lastName: 'Hector'};
7. return <Greeting {...props} />;
8. }
扩展运算符是一个es6特性。是一种传递属性的十分便利的方式。但请注意不要滥用该运算符,注意不要将一大堆毫不相关的prop一股脑全部传入下面的组件中。
共享结构的对象
希望大家都知道这种 ES6 的语法:
1. const obj = { a: 1, b: 2}
2. const obj2 = { ...obj } // => { a: 1, b: 2 }
const obj2 = { ...obj }
其实就是新建一个对象 obj2
,然后把 obj
所有的属性都复制到 obj2
里面,相当于对象的浅复制。上面的 obj
里面的内容和 obj2
是完全一样的,但是却是两个不同的对象。除了浅复制对象,还可以覆盖、拓展对象属性:
1. const obj = { a: 1, b: 2}
2. const obj2 = { ...obj, b: 3, c: 4} // => { a: 1, b: 3, c: 4 },覆盖了 b,新增了 c
我们可以把这种特性应用在 state
的更新上,我们禁止直接修改原来的对象,一旦你要修改某些东西,你就得把修改路径上的所有对象复制一遍,例如,我们不写下面的修改代码:
appState.title.text = '《React.js 小书》'
取而代之的是,我们新建一个 appState
,新建 appState.title
,新建 appState.title.text
:
1. let newAppState = { // 新建一个 newAppState
2. ...appState, // 复制 appState 里面的内容
3. title: { // 用一个新的对象覆盖原来的 title 属性
4. ...appState.title, // 复制原来 title 对象里面的内容
5. text: '《React.js 小书》' // 覆盖 text 属性
6. }
7. }
如果我们用一个树状的结构来表示对象结构的话:appState
和 newAppState
其实是两个不同的对象,因为对象浅复制的缘故,其实它们里面的属性 content
指向的是同一个对象;但是因为 title
被一个新的对象覆盖了,所以它们的 title
属性指向的对象是不同的。同样地,修改 appState.title.color
:
1. let newAppState1 = { // 新建一个 newAppState1
2. ...newAppState, // 复制 newAppState1 里面的内容
3. title: { // 用一个新的对象覆盖原来的 title 属性
4. ...newAppState.title, // 复制原来 title 对象里面的内容
5. color: "blue" // 覆盖 color 属性
6. }
7. }
我们每次修改某些数据的时候,都不会碰原来的数据,而是把需要修改数据路径上的对象都 copy 一个出来。这样有什么好处?看看我们的目的达到了:
1. appState !== newAppState // true,两个对象引用不同,数据变化了,重新渲染
2. appState.title !== newAppState.title // true,两个对象引用不同,数据变化了,重新渲染
3. appState.content !== appState.content // false,两个对象引用相同,数据没有变化,不需要重新渲染
修改数据的时候就把修改路径都复制一遍,但是保持其他内容不变,最后的所有对象具有某些不变共享的结构(例如上面三个对象都共享 content
对象)。大多数情况下我们可以保持 50% 以上的内容具有共享结构,这种操作具有非常优良的特性,我们可以用它来优化上面的渲染性能。
2、JSX中的Children
React组件中有一个特殊的prop–props.children
。它指代了JSX表达式中开闭标签中包含的内容。
下面讨论的是几种指定JSX的children的方法:
(1)使用字符串字面量
你可以直接在JSX的开闭标签中写入字符串字面量,组件得到的props.children就是该字符串值。
以下面的代码为例:
<MyComponent>Hello world!</MyComponent>
MyComponent的props.chilren将获得”Hello World!”字符串。通过该方式传入的字符串是未经HTML转义的。实际上你只需要像在HTML标签中写入文本那样就可以了。例如你想在一对<p>
标签中写入文本””,HTML和JSX写法是一样的,就像下面这样:
<p><script></script></p>
另外需要注意的是:
JXS会自动删除一行中开头和结尾处的空白符;JSX会自动删除空行;JSX会删除紧邻标签的换行;JSX会删除字符串中的换行;字符串中的换行会被转换成一个空格。
举例来说,下面的JSX代码都是等价的:
1. <div>Hello World</div>
2.
3. <div> Hello World </div>
4.
5. <div>
6. Hello World
7. </div>
8.
9. <div>
10. Hello
11. World
12. </div>
13.
14. <div>
15.
16. Hello World
17. </div>
(2)JSX元素作为children
我们同样可以使用JSX元素作为JSX的children,由此生成嵌套组件:
1. <MyContainer>
2. <MyFirstComponent />
3. <MySecondComponent />
4. </MyContainer>
我们也可以混合使用字符串字面量和JSX作为children:
1. <El>
2. Here is a list:
3. <ul>
4. <li>Item 1</li>
5. <li>Item 2</li>
6. </ul>
7. </El>
El的props.children将得到一个数组:
可以看到数组的第一个元素就是字符串“Here is a list:”,第二个元素是一个对象(JSX代表JavaScript对象)。
(3)JavaScript表达式
和prop一样,你也可以将任何有效的JavaScript表达式作为children传入,将它放在{}中就可以了。像下面这样:
<MyComponent>{'foo'}</MyComponent>
这里传入了一个常量表达式。
下面使用一个函数调用表达式来生成一个list作为children:
1. function Item(props) {
2. return <li>{props.message}</li>;
3. }
4.
5. function TodoList() {
6. const todos = ['finish doc', 'submit pr', 'nag dan to review'];
7. return (
8. <ul>
9. {todos.map((message) => <Item key={message} message={message} />)}
10. </ul>
11. );
12. }
当然你也可以在一个字符串children中插入一个JavaScript表达式来生成一个“模板”:
1. function Hello(props) {
2. return <div>Hello {props.username}!</div>;
3. }
(4)函数children
首先说明,这不是一种常见的用法。
实际上,传入自定义组件的children并没有严格的限制,只要在React需要render的时候能将它们转换成可以render的东西就行了。
下面是一个函数children的例子:
1. function ListOfTenThings() {
2. return (
3. <Repeat numTimes={10}>
4. {(index) => <div key={index}>This is item {index} in the list</div>}
5. </Repeat>
6. );
7. }
8.
9. // Calls the children callback numTimes to produce a repeated component
10. function Repeat(props) {
11. let items = [];
12. for (let i = 0; i < props.numTimes; i++) {
13. items.push(props.children(i));
14. }
15. return <div>{items}</div>;
16. }
实际上,我们更通常的情况下是将(index) => <div key={index}>This is item {index} in the list</div>
作为一个prop传入子组件。这个例子只是作为一种理解上的扩展。
(5)有关布尔值、Null以及Undefined
布尔值,Null以及Undefined可以作为有效的children,但他们不会被render,下面的JSX表达式都会render一个空的div标签:
1. <div />
2.
3. <div></div>
4.
5. <div>{false}</div>
6.
7. <div>{null}</div>
8.
9. <div>{true}</div>
关于此有一个有趣的应用,在条件render中,下面的<Header />
只有在show为true时才会render:
1. <div>
2. {showHeader && <Header />}
3. <Content />
4. </div>
3、注意事项
(1)使用JSX时要引入React库
前面已经解释过了,JSX是React.createElement
方法的语法糖,因此在使用JSX的作用域中必须引入React库。
如果你使用了JS打包工具,你可以在文件的头部作如下引用:
import React from 'react';
- 或者你不使用打包工具,也可以直接通过script标签引入React,比如: ```
- //本地
- //或者BootCDN
此时React将作为一个全局变量被引入,变量名就是’React’。<br />(2)注意引入JSX中用到的自定义组件<br />JSX中用到的组件可能并不会在JavaScript中直接引用到,但自定义组件本质上就是一个JS对象,你在JSX中使用的时候,需要首先将该组件引入到当前作用域:
- import MyComponent from ‘./MyComponent.js’
- …
(3)自定义组件首字母一定要大写<br />JSX中小写字母开头的element代表HTML固有组件如div,span,p,ul等。用户自定义组件首字母一定要大写如`<Header>`、`<Picker>`。<br />(4)元素标签名不能使用表达式<br />下面的代码将产生错误:
- const components = {
- photo: PhotoStory,
- video: VideoStory
- };
- function Story(props) {
- // Wrong! JSX标签名不能使用表达式
- return
; - }
如果你需要使用一个表达式来决定元素标签,你应该先将该表达式的值赋给一个**大写字母开头**的变量:
- const components = {
- photo: PhotoStory,
- video: VideoStory
- };
- function Story(props) {
- // Correct! JSX type can be a capitalized variable.
- const SpecificStory = components[props.storyType];
- return
; - }
``` | 《一》、理解JSX | | —- |(5)设置style属性<br />在设置标签style属性的时候,要注意,我们是将一个描述style的对象以JavaScipt表达式的形式传入。因此应该有2层大括号:
**JSX**
即**Javascrpt XML**
— — 一种在React
组件内部构建标签的类XML
语法。
**JSX**
并不是新语言,也没有改变JavaScript
的语法,只是一种基于ECMAScript
的新特性,一种定义带属性树结构(DOM
结构)的语法
React
可以不使用 JSX
来编写组件,但是使用 JSX
可以让代码可读性更高、语义更清晰、对 React
元素进行抽象等等。
一、使用JSX好处
1、允许使用熟悉的语法来定义HTML元素树 2、提供了更加语义化且易懂的标签
3、程序结构更容易被直观化 4、抽象了React Element
的创建过程
5、可以随时掌控HTML标签以及生成这些标签的代码 63、是原生Javascript
使用JSX和不使用JSX的代码对比如下:
1. //开闭标签,在构建复杂的树形结构时,比函数调用和对象字面量更易读
2. //#使用JSX
3. <div className="red">Children Text</div>;
4. <MyCounter count={3 + 5} />;
5. // 此处给一个js对象设置"scores"属性
6. var gameScores = {
7. player1: 2,
8. player2: 5
9. };
10. <DashboardUnit data-index="2">
11. <h1>Scores</h1>
12. <Scoreboard className="results" scores={gameScores} />
13. </DashboardUnit>;
14.
15. //#不使用JSX
16. React.createElement("div", { className: "red" }, "Children Text");
17. React.createElement(MyCounter, { count: 3 + 5 });
18.
19. React.createElement(
20. DashboardUnit,
21. { "data-index": "2" },
22. React.createElement("h1", null, "Scores"),
23. React.createElement(Scoreboard, { className: "results", scores: gameScores })
24. );
二、JSX 语法
【注意】 JSX
代码需经babel 编译成javscript,目前主流浏览器才能正常识别,即在head中需添加:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
React还需依赖的另外2个文件:react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能,
并将JSX
代码放在<script type='text/babel'>
… </script>
中编写
1. <!DOCTYPE html>
2. <html>
3. <head>
4. <meta charset="UTF-8" />
5. <title>Hello React!</title>
6. <script src="build/react.js"></script>
7. <script src="build/react-dom.js"></script>
8. <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
9. </head>
10. <body>
11. <div id="example"></div>
12. <script type="text/babel">
13. ReactDOM.render(
14. <h1>Hello, world!</h1>,
15. document.getElementById('example')
16. );
17. </script>
18. </body>
19. </html>
JSX
是HTML
和JavaScript
混写的语法,当遇到<**JSX**
就当**HTML**
解析,遇到 { 就当**JavaScript**
解析。
1. var names = ['Alice', 'Emily', 'Kate'];
2. ReactDOM.render(
3. <div>
4. {
5. names.map(function (name) {
6. return <div>Hello, {name}!</div>
7. })
8. }
9. </div>,
10. document.getElementById('example')
11. );
理解Array.prototype.map,返回一个新的数组
1. var friends = ['Jake Lingwall', 'Murphy Randall', 'Merrick Christensen'];
2. var listItems = friends.map(function(friend){
3. return "<li> " + friend + "</li>";
4. });
5. console.log(listItems); // ["<li> Jake Lingwall</li>", "<li> Murphy Randall</li>", "<li> Merrick Christensen</li>"];
JSX
允许直接在模板插入 JavaScript
变量。如果这个变量是一个数组,则会展开这个数组的所有成员
1. // arr变量是一个数组,结果 JSX 会把它的所有成员,添加到模板
2. var arr = [
3. <h1>Hello world!</h1>,
4. <h2>React is awesome</h2>,
5. ];
6. ReactDOM.render(
7. <div>{arr}</div>,
8. document.getElementById('example')
9. );
在React中,一个组件的HTML标签与生成这些标签的代码内在地紧密联系在一起。这意味和我们可以轻松地利用**Javascript**
强大魔力
1、使用三目运算符
1. render: function() {
2. return <div className={this.state.isComplete ? 'is-complete' : ''}>...</div>;
3. }
2、使用变量/函数
1. getIsComplete: function() {
2. return this.state.isComplete ? 'is-complete' : '';
3. },
4. render: function() {
5. var isComplete = this.getIsComplete();
6. return <div className={isComplete}>...</div>;
7.
8. //或者直接返回函数
9. return <div className={this.getIsComplete()}>...</div>;
10. }
3、使用逻辑与(&&)或者逻辑或( || )运算符
由于对于null或false值React不会输出任何内容,因此可以使用一个后面跟随了期望字符串的布尔值来实现条件判断。如果这个布尔值为true,后续字符串会被使用
1. render: function() {
2. return <div className={this.state.isComplete && 'is-complete'}>...</div>;
3. }
逻辑或,this.props.name为空时,className值等于is-complete
1. render: function() {
2. return <div className={this.props.name || 'is-complete'}>...</div>;
3. }
4、函数调用
1. var HelloWorld = React.createClass({
2. render: function () {
3. return <p>Hello, {(function (obj) {
4. return obj.props.name ? obj.props.name : "World";
5. })(this)}</p>
6. }
7. });
三、创建并渲染组件
1. //1、React.createClass 是用来创建一个组件
2. var HelloMessage = React.createClass({
3. render: function() {
4. return <h1>Hello {this.props.name}</h1>;
5. }
6. });
7. //2、ReactDOM.render渲染组件
8. ReactDOM.render(
9. <HelloMessage name="John" />,
10. document.getElementById('example')
11. );
《二》、JSX和HTML不同点 |
---|
一、渲染HTML标签和React组件
React.render
方法可以渲染HTML
结构,也可以渲染React
组件。
1、渲染HTML
标签,声明变量采用首字母小写
1. var myDivElement = <div className="foo" />;
2. ReactDOM.render(myDivElement, document.body);
2、渲染React
组件,声明变量采用首字母大写
1. var MyComponent = React.createClass({/*...*/});
2. var myElement = <MyComponent someProperty={true} />;
3. ReactDOM.render(myElement, document.body);
二、非DOM属性
1、键(key
)
key
是一个可选的唯一标识符,当两个已经在于DOM
中的组件交换位置时,React
能够匹配对应的key
并进行相应的移动,且不需要完全重新渲染DOM
,提供渲染性能
2、引用(ref
)
**ref**
允许父组件在**render**
方法之外保持对子组件的一个引用。在JSX
中,你可以通过属性中设置期望的引用名来定义一个引用。
1. render: function() {
2. return <div>
3. <input ref="myInput" ...> </input>
4. </div>
5. );
6. }
然后你可以在组件的任何地方使用this.refs.myInput
获取这个引用了。通过引用获取到的这个对象被称为支持实例。它并不是真的DOM
,而是React在需要时用来创建DOM
的一个描述对象。你可以使用this.refs.myInput.getDOMNode()
访问真实的DOM
节点。
3、设置原始的HTML
比如我们有一些内容是用户输入的富文本,希望展示相应的样式
1. var content='<strong>content</strong>';
2. ReactDOM.render(
3. <div>{content}</div>,
4. document.body
5. );
结果页面直接输出内容了: React
默认会进行HTML
的转义,避免XSS
攻击,如果要不转义,可以这么写:
1. ReactDOM.render(
2. <div dangerouslySetInnerHTML={{__html: "<strong>content</strong>"}}></div>,
3. document.body
4. );
三、事件
在所有的浏览器中,事件名已经被规范化并统一用onXXX驼峰形式表示
1. var BannerAd = React.createClass({
2. handleClick: function(event) {
3. //...
4. },
5. render: function() {
6. return <div onClick={this.handleClick}>Click Me!</div>;
7. }
8. })
【注意】 React自动绑定了组件所有方法的作用域,因此你不需要手动绑定
1. handleClick: function(event) {...},
2. render: function() {
3. //反模式 ————在React中手动给组件实例绑定
4. //函数作用域是没有必要的
5. return <div onClick={this.handleClick.bind(this)}>...</div>;
6. }
四、特殊属性
由于JSX会转换为原生的Javascript函数,因此有一些关键词我们是不能用的——如**class**
和**for**
,对应JSX中属性写成**className**
和**htmlFor**
1. //#使用JSX
2. ReactDOM.render(
3. <label className="xxx" htmlFor="input">content</label>,
4. document.getElementById('example')
5. );
6. //#不使用JSX
7. ReactDOM.render(
8. React.createElement('label', {className: 'xxx', htmlFor: 'input'}, 'content'),
9. document.getElementById('example')
10. );
五、style样式
React
把所有的内联样式都规范化为驼峰形式,与Javascript
中DOM
的sytle
属性一致。第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。
React.render(
<div style={{color:'red'}}>
xxxxx
</div>,
document.body
);
var style = {
color:'red',
borderColor: '#999'
}
ReactDOM.render(<div style={style}>xxxxx</div>, document.body);
六、注释JSX
本质就是Javascript
,因此你可以在标签内添加原生的javascript
注释。
- 注释两种形式
- 当作一个元素的子节点
- 内联在元素的属性中
| 《三》、JSX延伸属性 | | —- |var content = (
<Nav>
{/* 一般注释, 用 {} 包围 */}
<Person
/* 多
行
注释 */
name={window.isLoggedIn ? window.name : ''} // 行尾注释
/>
</Nav>
);
一、不要改变props
如果提前就知道了组件的属性的话,写起来很容易。例如component
组件有两个动态的属性foo和bar:
var component = <Component foo={x} bar={y} />;
而实际上,有些属性可能是后续添加的,我们没办法一开始就确定,我们可能会写出下面不好的代码:
1. var component = <Component />;
2. component.props.foo = x; // bad
3. component.props.bar = y; // also bad
这样写是错误的,因为我们手动直接添加的属性React
后续没办法检查到属性类型错误,也就是说,当我们手动添加的属性发生类型错误时,在控制台是看不到错误信息的。
在React
的设定中,初始化完props
后,props
是不可变的。改变props
会引起无法想象的后果。
二、延伸属性
为了解决这个问题,React
引入了属性延伸
1. var props = {};
2. props.foo = x;
3. props.bar = y;
4. var component = <Component {...props} />;
当需要拓展我们的属性的时候,定义个一个属性对象,并通过{...props}
的方式引入,React
会帮我们拷贝到组件的props
属性中。重要的是—这个过程是由React
操控的,不是手动添赋值的属性。
需要覆盖的时候可以这样写:
1. var props = { foo: 'default' };
2. var component = <Component {...props} foo={'override'} />;
3. console.log(component.props.foo); // 'override'
《四》、JSX 陷阱 |
---|
一、自定义HTML属性
如果往原生 HTML
元素里传入 HTML
规范里不存在的属性,React
不会显示它们。
1. ReactDOM.render(
2. <div dd='xxx'>content</div>,
3. document.body
4. );
如果需要使用自定义属性,要加 data- 前缀。
1. ReactDOM.render(
2. <div data-dd='xxx' aria-dd='xxx'>content</div>,
3. document.body
4. );
二、组件render渲染函数中return注意点
如果return和JSX语句开头在同一行时,不需要括号;否则要括号包裹
1. //正确写法1
2. var HelloMessage = React.createClass({
3. render: function() {
4. return <h1>
5. Hello {this.props.name}</h1>;
6. }
7. });
8. //正确写法2
9. render: function() {
10. return <h1>Hello {this.props.name}</h1>;
11. }
12. //正确写法3
13. render: function() {
14. return (
15. <h1>Hello {this.props.name}</h1>);
16. }
17.
18. //错误写法
19. render: function() {
20. return
21. <h1>Hello {this.props.name}</h1>;
22. }
React.createElement(component, props, …children)的形式,比如:
1. <MyButton color="blue" shadowSize={2}>
2. Click Me
3. </MyButton>
编译结果:
1. React.createElement(
2. MyButton,
3. {color: 'blue', shadowSize: 2},
4. 'Click Me'
5. )
当然,你也可以使用自闭和的形式:
<div className="sidebar" />
可以得到相同的编译结果。
1.指定React元素的类型
JSX标签的头部,决定了React元素的类型,大写的标签,意味着JSX的标签与React的组件一一对应,比如
<Foo/>标签就对应了Foo组件
(1)必须包裹在一定的范围内
1. import React from 'react';
2. import CustomButton from './CustomButton';
3.
4. function WarningButton() {
5. // return React.createElement(CustomButton, {color: 'red'}, null);
6. return <CustomButton color="red" />;
7. }
比如这样,引入了2个组件,构成了一个新的组件WarningButton,组件的返回值的元素,必须包含在一定范围内,这里通过函数的’{ ‘, ’ } ‘实现包裹的效果。
(2)用户定义的组件必须大写
我们前面已经说过,JSX的标签与组件是一一对应的,当我们使用JSX语法,引用组件的时候,标签必须要大写(同时定义组件的函数名也必须是大写的)。
1. function Hello(){
2. return <h2>Hello,World</h2>
3. }
4. //定义过程
5. <Hello/>
6. //使用过程
(3)不能在运行期间,动态的选择类型
我们不能在JSX中,动态的规定组件的类型,举例来说:
1. import React from 'react';
2. import { PhotoStory, VideoStory } from './stories';
3.
4. const components = {
5. photo: PhotoStory,
6. video: VideoStory
7. };
8.
9. function Story(props) {
10. return <components[props.storyType] story={props.story} />;
11. //这样写是不对的,我们在返回的组件中,动态定义了组件,这种动态的定义是无效的
12. }
应该改写为:
1. import React from 'react';
2. import { PhotoStory, VideoStory } from './stories';
3.
4. const components = {
5. photo: PhotoStory,
6. video: VideoStory
7. };
8.
9. function Story(props) {
10.
11. const SpecificStory = components[props.storyType];
12. return < SpecificStory story={props.story} />;
13. //这样就是正确的,我们不要在JSX的标签中使用动态定义
14. }
2.JSX中的Props属性
(1)JS表达式
可以通过{},包裹js的语法来使用。比如:
<MyComponent foo={1 + 2 + 3 + 4} />
等价于:
<MyComponent foo={10} />
如果不是js表达式,则不能包裹在{}中使用。
(2)Props属性的默认值
Props上的属性可以有默认值,并且默认值为true,比如:
1. <MyTextBox autocomplete />
2.
3. <MyTextBox autocomplete={true} />
上面这两个式子是等价的,但是不推荐使用默认值,因为在ES6的语法中{foo}代表的意思是:{foo:foo}的意思,并不是{foo:true}。
(3)扩展属性
可以通过ES6的…方法,给组件赋属性值,例如:
1. function App1() {
2. return <Greeting firstName="Ben" lastName="Hector" />;
3. }
4.
5. function App2() {
6. const props = {firstName: 'Ben', lastName: 'Hector'};
7. return <Greeting {...props} />;
8. }
上面的这两种方式是等价的。
3.JSX中的children
(1)children中的function
我们来考虑自定义组件中包含函数的情况:
1. function ListOfTenThings() {
2. return (
3. <Repeat numTimes={10}>
4. {(index) => <div key={index}>This is item {index} in the list</div>}
5. </Repeat>
6. );
7. }
那么何时调用这个children中的方法呢?
1. function Repeat(props) {
2. let items = [];
3. for (let i = 0; i < props.numTimes; i++) {
4. items.push(props.children(i));
5. }
6. return <div>{items}</div>;
7. }
我们从上述的Repeat组件的定义中可以看出来,children中的方法按此定义会一直执行10次。
(2)忽略Boolean,Null以及Undefined
false,null,undefined以及true是不能通过render()方法,呈现在页面上的,下面的这些div块的样式
相同,都是空白块:
1. <div />
2.
3. <div></div>
4.
5. <div>{false}</div>
6.
7. <div>{null}</div>
8.
9. <div>{true}</div>
这种属性,在通过render呈现元素的时候,是十分有用的,比如我们只想在div元素中展现Head组件,
例子如下:
1. <div>
2. {showHeader && <Header />}
3. <Content />
4. </div>
这里的逻辑是,只有showHeader==true,在会在页面呈现Header组件,否则为null,即为不显示任何东西,这相当于一个if的判断了。
再举一个例子:
1. <div>
2. {props.messages.length &&
3. <MessageList messages={props.messages} />
4. }
5. </div>
在这个div中,我们需要知道的是即使元素为0,0是能够呈现在页面中的。也就是说上述代码中,只要
props.messages数组存在,不管长度是否为0都是存在的。(这里不同于js,js中的语法认为0==false)
(3)如何显示Null,Undefined和Boolean
如果我们一定要再页面上显示Null等,可以将其先转化为字符串之后再显示。
1. <div>
2. My JavaScript variable is {String(myVariable)}.
3. </div>
结语
JSX在React中使用给我们带来了很大的便利,JSX的语法实际上十分简单也很容易掌握。祝学习愉快。
欢迎点击 我的小站
本文地址 JSX语法详解
一、为什么使用JSX
1、JSX看起来像是XML的JavaScript语法扩展。React可以用来做简单的JSX语法转换。
不需要为了React使用JSX可以使用JS创建,但建议使用JSX,因为可以使定义简洁且我们素质的包含属性的树状结构语法。XML有固定的标签开启和闭合,这能让复杂的树更易于阅读,优于方法调用和队形字面量的形式。
二、JSX使用
1、HTML标签与React组件对比
React可以渲染HTML标签(strings)或者React组件(classes)。
要渲染HTML标签:只需在JSX里使用小写字母开头的标签名。例如:
1. var myDivElement= <div className="foo"/>;
2.
3. React.render(myDivElement,document.body);
要渲染React组件只需创建一个大写字母开头的本地变量:
1. var MyComponent =React.createClass({/*...*/});
2.
3. var myElement= <MyComponent someProperty={true}/>; React.render(myElement,document.body);
React的JSX里约定分别使用首字母大小写区别本地组件的类和HTML标签。
PS:由于JSX就是JavaScrript,一些标识想是class和for不建议作为XML属性名,作为代替,React DOM使用className和htmlfor来做对应的属性。
2、转换
JSX把类XML的语法转换成纯粹JavaScript,XML元素、属性、和子节点被转换成React.creatElement的参数。
PS:JSX总是当作ReactElement执行,具体的实际细节可能不同。
3、JavaScript表达式
属性表达式:
要使用JavaScript表达式作为属性值,只需要把这个表达式用一对大括号包起来,不要用(“”)。例如:
1. //输入(JSX)
2.
3. var person =<Person name ={window.isLoggedIn?window.name:''}/>
4.
5. //输出(JS)
6.
7. var person =React.createElement(
8.
9. Person,
10.
11. {name:window.isLoggedIn?window.name : ''}
12.
13. };
14.
4、子节点表达式
同样的JavaSCript表达式可用于表述子节点
1. // 输入 (JSX):
2.
3. varcontent = <Container>{window.isLoggedIn? <Nav/> : <Login/>}</Container>;
4.
5. // 输出 (JS):
6.
7. varcontent =React.createElement(
8.
9. Container,
10.
11. null,
12.
13. window.isLoggedIn? React.createElement(Nav): React.createElement(Login)
14.
15. );
注释
JSX里添加注释很容易;他们只是JS表达式而已。你只要在一个标签的子节点内(非最外层)小心地用{}包围要注释的部分。
1. var content = (
2.
3. <Nav>
4.
5. {/*一般注释,用 {}包围 */}
6.
7. <Person
8.
9. /*多
10.
11. 行
12.
13. 注释 */
14.
15. name={window.isLoggedIn ? window.name : ''} //行尾注释
16.
17. />
18.
19. </Nav>
20.
21. );
22.
三、JSX的延展属性
1、
varcomponent =
component.props.foo= x; // 不好
component.props.bar= y; // 同样不好
这样是反模式出现错误React不会见长属性类型,有错误就不可以提示,props应该被禁止修改,修改后可能导致预料之外的结果。
2、延展属性(Spread Attributes)
var props ={};
props.foo =x;
props.bar=y;
var component =
传入组件的属性会被复制到组件内。它能多次使用也可以与其他属性一起用。
var props= {foo:‘default’}
var component =
console.log(component.props.foo);//‘override’
PS: …这三个点是操作符(也被叫做延展操作符-spread operator)已经被ES6数组支持。相关的还有ES7规定草案中的Object剩余和延展属性(Rest and Spread Properties)。
四、JSX的陷阱
1、JSX与HTML很相似但是还是存在一些关键的区别。
首先与DOM的区别,如行内样式style。
React 为了性能和跨浏览器的原因,实现了一个独立于浏览器的事件和 DOM 系统。利用此功能,可以屏蔽掉一些浏览器的 DOM 的粗糙实现。
- 所有 DOM 的 properties 和 attributes (包括事件处理器)应该都是驼峰命名的,以便和标准的 JavaScript 风格保持一致。我们故意和规范不同,因为规范本身就不一致。然而,data- 和 aria- 属性符合规范,应该仅是小写的。
- style 属性接收一个带有驼峰命名风格的 JavaScript 对象,而不是一个 CSS 字符串。这与 DOM 中的 style 的 JavaScript 属性保持一致,更加有效,并且弥补了 XSS 安全漏洞。
- 所有的事件对象和 W3C 规范保持一致,并且所有的事件(包括提交事件)冒泡都正确地遵循 W3C 规范。参考事件系统获取更多详细信息。
- onChange 事件表现得和你想要的一样:当表单字段改变了,该事件就被触发,而不是等到失去焦点的时候。我们故意和现有的浏览器表现得不一致,是因为 onChange 是它的行为的一个错误称呼,并且 React 依赖于此事件来实时地响应用户输入。参考表单获取更多详细信息。
- 表单输入属性,例如 value 和 checked,以及 textarea。这里有更多相关信息。
2、HTML实体
可以插入到JSX的文本中。如果JSx表达表达式中显示HTML实体,可以回遇到二次转义的问题。因为React默认会转义所有字符串,为了防止各种XSS攻击。
1. 当:<div>First· Second</div>时候会:
2.
3. // 错误: 会显示 “First · Second”
4.
5. <div>{'First · Second'}</div>
有多种绕过的方法。最简单的是直接用 Unicode 字符。这时要确保文件是 UTF-8 编码且网页也指定为 UTF-8 编码。
安全的做法是先找到 实体的 Unicode 编号 ,然后在 JavaScript 字符串里使用:
1. <div>{'First \u00b7 Second'}</div>
2.
3. <div>{'First ' + String.fromCharCode(183)+ ' Second'}</div>
可以在数组里混合使用字符串和 JSX 元素:
<div>{['First ', <span>·</span>, ' Second']}</div>
万万不得已时候使用原始的HTML。
3、自定义HTML属性
如果向原生HTML元素里传入HTML规范里不存在的属性,React不会显示它们。如果需要使用自定义属性,要加data-前缀。
<div data-custom-attribute="foo"/>
以 aria- 开头的 [网络无障碍] 属性可以正常使用。
<div aria-hidden={true}/>
React普通样式(className)和行内样式(LineStyle)多种设置样式设置详解
1.使用className设置样式(CSS的其他选择器也是同理)
(1)定义一个CSS文件style.css,和普通CSS一样定义class选择器
1. .sty1{//和普通CSS一样定义class选择器
2.
3. background-color: red;
4.
5. color: white;
6.
7. font-size: 40px;
8.
9. }
(2)在JSX中导入编写好的CSS文件
import './style.css';
(3)JSX的调用
<div className="sty1">看背景颜色和文字颜色</div>
说明:id选择器也是同理,由于React使用ES6编写代码,而ES6又有class的概念,所以为了不混淆class选择器在React中写成了className
可能你在看别人的代码的时候可能看到以下代码,这个是通过CSS Modules的写法
(1)定义一个CSS文件styleother.css,和普通CSS一样定义class选择器
1. .sty2{//和普通CSS一样定义class选择器
2.
3. background-color: red;
4.
5. color: white;
6.
7. font-size: 40px;
8.
9. }
(2)在JSX中导入编写好的CSS文件
import StyleOther from './styleother.css';
(3)JSX的调用
<div className={StyleOther.sty2}>看背景颜色和文字颜色</div>
说明:使用这种方式也是可以的,只是你需要修改你的webpack的config文件,将loader: “style!css”修改为loader: “style!css?modules”,在css后面加一个modules,不过这两种方式是不能同时存在的,因为加了modules,
详细资料:点击打开链接
2.使用React的行内样式样式设置样式
(1)在JSX文件中定义样式变量,和定义普通的对象变量一样
1. let backAndTextColor = {
2.
3. backgroundColor:'red',
4.
5. color:'white',
6.
7. fontSize:40
8.
9. };
(2)JSX的调用
<div style={backAndTextColor}>看背景颜色和文字颜色</div>
当然你也可以不定义一个变量,直接写到JSX中,如下代码所示:
<div style={{backgroundColor:'red',color:'white',fontSize:40}}>看背景颜色和文字颜色</div>
分析:style={},这里的{}里面放的是对象,不管你是定义一个对象然后使用,还是直接在里面写对象都是可以的,甚至可以写成下面的样子
1.
2. style={this.getInputStyles()}
3.
4. getInputStyles方法根据不同的状态返回不同的样式
5.
6. getInputStyles() {
7.
8. let styleObj;
9.
10. if (this.state.focused == true) {
11.
12. styleObj = {outlineStyle: 'none'};
13.
14. }
15.
16. return styleObj;
17.
18. }
3.React行内样式扩展
在 React 中,行内样式并不是以字符串的形式出现,而是通过一个特定的样式对象来指定。在这个对象中,key 值是用驼峰形式表示的样式名,而其对应的值则是样式值,通常来说这个值是个字符串,如果是数字就不是字符串,不需要引号。
1. var divStyle = {
2.
3. color: 'white',
4.
5. backgroundImage: 'url(' + imgUrl + ')',
6.
7. WebkitTransition: 'all', // 注意这里的首字母'W'是大写
8.
9. msTransition: 'all' // 'ms'是唯一一个首字母需要小写的浏览器前缀
10.
11. };
另外浏览器前缀除了ms以外首字母应该大写,所以这里的WebkitTransition的W是大写的。
当为内联样式指定一个像素值得时候, React 会在你的数字后面自动加上 “px” , 所以下面这样的写法是有效的:
1. let backAndTextColor = {
2.
3. backgroundColor:'red',
4.
5. color:'white',
6.
7. fontSize:40
8.
9. };
有时候你的确需要保持你的CSS属性的独立性。下面是不会自动加 “px” 后缀的 css 属性列表:
1. columnCount
2.
3. fillOpacity
4.
5. flex
6.
7. flexGrow
8.
9. flexShrink
10.
11. fontWeight
12.
13. lineClamp
14.
15. lineHeight
16.
17. opacity
18.
19. order
20.
21. orphans
22.
23. strokeOpacity
24.
25. widows
26.
27. zIndex
28.
29. zoom
注释技巧:在React里注释不能用HTML的方式,那是木有用的。也不能直接用js的注释,那也是不行的。而是用大括号括起来,之后用/**/来注释,看起来是这样的
{/* 这是一个注释 */}
React普通样式(className)和行内样式(LineStyle)多种设置样式设置详解
参考链接:
1、《React学习笔记—JSX》https://segmentfault.com/a/1190000002646155
2、《React引领未来的用户界面开发框架》
3、http://facebook.github.io/react/docs/jsx-in-depth.html
4、http://www.jikexueyuan.com/course/969_3.html?ss=1
5、http://buildwithreact.com/tutorial/jsx