React
網頁總是一個 連結 著另一個的, React
一大優勢在於每次 連結 到另一個頁面上去的時候,不需要向傳統頁面一樣,得 銷燬 所有程式碼, 重新渲染 新頁面的程式碼,而只在一個頁面上展現新的內容—— 單頁頁面 。
React
另一個優勢是,以往的 單頁頁面 你需要考慮哪個元素要被刪除、哪個元素的行為要被修改,而我們只需要告訴 React
我們想要的最終頁面的效果, React
會自動幫我們處理頁面上的元素,做刪除、修改等操作。
而我只知道 React
有自己的 虛擬DOM ,它會對比 虛擬DOM和真實DOM的差別 ,然後在適當的時機更新頁面。至於它怎麼對比的?怎麼知道差別的?怎麼進行修改的?我不知道,不過,對於我們,誰在乎呢?
必須首先知道的關於 React
的術語
-
JSX
語法:React
特有語法,用來搭建 虛擬DOM - 元件(
Component
):一個個程式碼塊,用來封裝各種功能,可以類比於函式(function
) -
props
&status
:元件的所有靜態屬性 & 所有動態屬性
引入 React
想要使用 React
,你需要先引入:
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin</script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
上面兩個 <script>
引入了 React
的核心庫 ,最後一句 <script>
引入 jsx
語法編譯器 ,因為瀏覽器不懂 jsx
只知道 javascript
,所以,引入編譯器轉換為瀏覽器能懂的 javascript
語言
請參考 React
官方文件以獲取最新版本 React
的引入: https://reactjs.org/docs/add-...
初步使用 React
並沒有什麼特別的技巧,先看程式碼,再做解釋:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React First Try</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); ReactDOM.render( <div> <p>Batman</p> <p>catwoman</p> </div>, container ); </script> </body> </html>
解釋:
- 首先引入了三個
<script>
- 新建一個元素
<div id="container"></div>
- 我們必須在一個
<scripr type="text/babel">
中使用React
,請注意<script>
的type
-
像一般的
javascript
語法一樣,我們先獲取頁面元素var container = document.querySelector("#container");
-
修改 虛擬DOM ,並渲染 真實DOM
其中,
ReactDOM.render();
就是在渲染,其含義是將第一個引數渲染到第二個引數下。而第一個引數<div>...</div>
就是新的 虛擬DOM 的內容,可更改為我們想要的 真實DOM 結構。ReactDOM.render( <div> <p>Batman</p> <p>catwoman</p> </div>, container );
- 效果、頁面結構
- 我們看到,頁面中已經添加了包含兩個
<p>
元素的<div>
。React.render()
函式的第一個引數只能是一個標籤,不能是並列的兩個標籤。不過一個標籤裡的子標籤可以隨便的新增,所以最好的方法就是,在外面新增一個<div></div>
使用元件( Component
)
上面的方法是直接將你想要的寫在 React.render()
裡,通常的做法是引用元件
-
定義一個元件
class 元件名 extends React.Component( //your code );
-
元件裡可以新增很多功能,比如想要新增一個按鈕,你只需直接寫你想要的DOM結構,而不需要使用
javascript
語法:createElement()
、appendChild()
等class 元件名 extends React.Component( render(){ return (<button>Batman</button>); } );
-
在元件裡寫好你想要的東西,使用
React.render()
進行渲染React.render( <元件名/>, 想要渲染的位置 )
-
完整程式碼可以如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React First Try</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); class Myname extends React.Component{ render(){ return (<button>Batman</button>); } }; ReactDOM.render( <Myname/>, container ); </script> </body> </html>
- 效果、頁面結構
- 我們看到,頁面上出現了我們想要的按鈕,頁面結構裡也成功添加了
<button>
標籤。 注意!!!元件名首字母必須大寫!!!引用元件注意程式碼<元件名/>
,一個符號都不能錯的!!!
使用 props
props
用來獲取元件的靜態屬性,可以先看下面的一個小例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React First Try</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); class Myname extends React.Component{ render(){ return (<button type={this.props.buttontype}>{this.props.children}</button>); } }; ReactDOM.render( <Myname buttontype="submit">Batman</Myname> , container ); </script> </body> </html>
不必驚慌,修改的地方只有元件的 render()
和實際渲染的 render()
兩個函式。
- 第一個
render()
添加了<button>
的type
屬性,該屬性值指向{this.props.buttontype}
,意思是該元件名為buttontype
的靜態屬性。這個render()
還將<button>
的顯示文字指向{this.props.children}
,意思是該元件的子元素這個靜態屬性 - 第二個
render()
函式添加了<Myname>
的靜態屬性buttontype
,和一個text
型別的子元素Batman
- 結論就是: 在渲染真實DOM的時候,會建立一個
<button></button>
標籤,它的type
屬性值為submit
,文字顯示為Batman
- 效果、頁面結構,哈哈哈,沒啥區別,沒區別就對了:
props
的傳遞性
props
只能從父元素向下傳遞給子元素:
當有多個屬性你想傳遞的時候,你的程式碼可能就會是這樣的,會重複很多遍 {this.props.propsName}
:
<script> class Me extends React.Component{ render(){ return ( <div> <p>{this.props.props1}</p> <p>{this.props.props2}</p> <p>{this.props.props3}</p> </div> ); } }; class Father extends React.Component{ render(){ return ( <Me props1={this.props.props1} props2={this.props.props2} props3={this.props.props3}/> ); } }; ReactDOM.render( <Father props1="a" props2="b" props3="c"/>,container ); </script>
如果你不想重複很多遍繁瑣的 {this.props.propsName}
,那你可以使用 擴充套件運算子 ...
表示取到所有的靜態屬性並且都使等於 {this.props.propsName}
,所以我們的程式碼可以稍作簡化:
<script> class Me extends React.Component{ render(){ return ( <div> <p>{this.props.props1}</p> <p>{this.props.props2}</p> <p>{this.props.props3}</p> </div> ); } }; class Father extends React.Component{ render(){ return ( <Me {...props}/>//:point_left::point_left:使用擴充套件運算子進行簡化{...props} ); } }; ReactDOM.render( <Father props1="a" props2="b" props3="c"/>,container ); </script>
React
操作 CSS
此方法可以使你在 <script>
裡更改、渲染 CSS
。不過使用 React
的 JSX語法
會和 CSS語法
有一點點不同,就一點點┑( ̄Д  ̄)┍
因為剛開始接觸,程式碼不難,所以直接先看示例程式碼吧;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React First Try</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); class Mycss extends React.Component{ render(){ var letterColor = { padding: 10, margin: 10, backgroundColor: this.props.thiscolor, color: "#333", display: "inline-block", fontFamily: "monospace", fontSize: 32, textAlign: "center", }; return (<div style={letterColor}>{this.props.children}</div>); } }; ReactDOM.render( <div> <Mycss thiscolor="#58B3FF">B</Mycss> <Mycss thiscolor="#FF605F">a</Mycss> <Mycss thiscolor="#FFD52E">t</Mycss> <Mycss thiscolor="#49DD8E">m</Mycss> <Mycss thiscolor="#AE99FF">a</Mycss> <Mycss thiscolor="#FF6633">n</Mycss> </div> , container ); </script> </body> </html>
- 哇!!程式碼怎麼看上去又有這麼多的改動啊!!別慌張別慌張!其實和上一小節一樣,只改動了一些內容在元件的
render()
和真實渲染的render()
兩個函式裡 -
元件
render()
裡首先定義了一個虛擬CSS類
,看上去符合CSS語法
,但其實呢,他是一個JSX語法
,仔細看,它就是一個用JSX語法
寫的神似CSS
的 物件 。其中的一些區別如下:- 它不應該有
px
,px
這種東西JSX
會自動補充
- 它不應該有分號
;
來表示這個屬性結束了,請使用逗號,
- 它應該把 除了純數字外的所有屬性值 都加上引號
""
- 它應該使用 駝峰命名法 來表示
CSS
中 使用連線號-
的屬性名:backgroundColor
- 它不應該有
- 所以,在遵循了所有使用
JSX語法
描述CSS
狀態的規則之後,你就可以成功的定義一個 虛擬CSS 。接著,在元件的render()
裡呼叫它,像這樣<div style={letterColor}>
,style={虛擬CSS名}
。 - 在這裡另一個知識點是,在定義 虛擬CSS 的
backgroundColor
時,它的引數值是一個變數this.props.thiscolor
,同上一小節一樣,在真實渲染render()
的第一個引數裡定義這個靜態變數<Mycss thiscolor="#58B3FF">
。這樣,就成功在CSS
(虛擬的)裡呼叫了其它地方的變數來確定屬性值。 - 效果、頁面結構:值得注意的是,
React
處理的CSS
是通過內聯方式(標籤中插入style
屬性)實現的
小結
這個時候,我們需要做一個小例子,來鞏固下關於 元件 、 CSS引入 、 props 的概念
我們想要實現的效果
我們想要實現的效果就是,當你輸入顏色程式碼,上面就能正確的展示顏色:
分離元件
在 React
的世界,一切都是元件,頁面上所有的內容都是由一個個元件搭建起來的。你可以將結構劃分為很小的元件,這樣實現的功能就很詳細。你也可以將結構劃分為稍大的元件,功能就更集中。
所以,像我們這樣的小應用,下面的元件劃分方法就足以滿足要求:
編寫程式
在分析完結構需要分成多少元件之後,可以開始構造程式碼~
-
首先,我們編寫元件框架。其中每一個
class
就代表了我們分成的元件。在這裡class ColorName
表示文字部分,class Color
表示顏色顯示區,class Board
表示用來承載這個應用的底板。每個元件都有一個render()
函式用來之後渲染元件到DOM上。<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Color</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); class ColorName extends React.Component{ render(){ } }; class Color extends React.Component{ render(){ } }; class Board extends React.Component{ render(){ } }; ReactDOM.render( <Board/>,container ); </script> </body> </html>
-
上述步驟等於搭完了骨架,我們需要填充肌肉。寫下,最終需要每個元件分別返回什麼標籤:
ColorName
元件返回一個<p>
標籤,用以展現顏色的色號Color
元件返回一個<div>
標籤,用來顯示顏色Board
元件返回一個<div>
標籤,並且把上兩個元件包在一起<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Color</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); class ColorName extends React.Component{ render(){ return (<p>{this.props.colorName}</p>); } }; class Color extends React.Component{ render(){ return (<div id="color"></div>); } }; class Board extends React.Component{ render(){ return ( <div> <Color colorName = {this.props.colorName}/> <ColorName colorName = {this.props.colorName}/> </div> ); } }; ReactDOM.render( <Board colorName="#f7a87d"/>,container ); </script> </body> </html>
- 接下來我們只需要新增你想要的
CSS
就OK了,不過在新增CSS
之前,我想對上一步驟簡單解釋:我們在渲染 真實DOM 時定義了一個靜態屬性colorName="#f7a87d"
,經由元件Board
傳入元件ColorName
、Color
。最後通過每個元件各自的render()
函式的return
渲染在頁面上。 -
最後我們需要新增一些
CSS
幫頁面穿點衣服,其中對CSS
的引入使用了兩種方法,使用React
引入和引入外部CSS
檔案:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Color</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <style> #board{ width: 300px; height: 400px; /* border: 1px solid red; */ border-radius: 3%; box-shadow: 3px 5px 7px 1px rgba(128,128,128,1); } #color{ height: 80%; border-radius: 3%; box-shadow: 1px 1px 6px 1px rgba(128,128,128,1); } </style> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); class ColorName extends React.Component{ render(){ var ColorNameStyle = { fontSize: "2.5em", fontFamily: "sans-serif", fontWeight: "bold", textAlign: "center", margin: 17, }; return (<p style={ColorNameStyle}>{this.props.colorName}</p>); } }; class Color extends React.Component{ render(){ var colorStyle = { backgroundColor: this.props.colorName, }; return (<div style={colorStyle} id="color"></div>); } }; class Board extends React.Component{ render(){ return ( <div id="board"> <Color colorName = {this.props.colorName}/> <ColorName colorName = {this.props.colorName}/> </div> ); } }; ReactDOM.render( <Board colorName="#f7a87d"/>,container ); </script> </body> </html>
使用 state
以上的各個步驟可以建立一個基本的靜態頁面,如果想要建立一個有點動態,看上不是死氣沉沉的頁面,那就一定需要 state
。正如之前提到的, props
包含了所有的靜態屬性, state
則包含了所有用於動態展示的屬性。
這時,我們需要一個例子
我們的目標
分離元件
外面一個黑的長方形邊框;內部一個黑色的底板; #5dffff
的動態數字;三行文字
編寫程式碼
-
編寫程式碼框架:
Times
類表示變化的數字;Words
表示三行灰色的文字;BlackBoard
表示黑色的底板;Board
表示最外面一圈黑邊框<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Lightning</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); class Times extends React.Component{ render(){ return (); } }; class Words extends React.Component{ render(){ return (); } }; class BlackBoard extends React.Component{ render(){ return (); } }; class Board extends React.Component{ render(){ return (); } }; ReactDOM.render( <Board/> ,container ); </script> </body> </html>
-
然後我們需要添上返回的內容,我們就只看
React
的內容<script type="text/babel"> var container = document.querySelector("#container"); class Times extends React.Component{ render(){ return (<h1>Strike Times</h1>); } }; class Words extends React.Component{ render(){ return ( <div> <p>lightning strike</p> <p>worldwide</p> <p>(since you loaded this outstanding)</p> </div> ); } }; class BlackBoard extends React.Component{ render(){ return ( <div> <Times/> <Words/> </div> ); } }; class Board extends React.Component{ render(){ return ( <div> <BlackBoard/> </div> ); } }; ReactDOM.render( <Board/> ,container ); </script>
-
將
Strike Times
變成動態,我們只需改變Times
類:-
首先需要定義
state
:必須在constructor
內定義this.state={}
constructor(props){ super(props); this.state = { strike: 0, }; }
-
使用 生命週期鉤子 ,
componentDidMount
鉤子裡的內容會在頁面渲染完成後被呼叫.在本例中,頁面渲染完成後會呼叫一個計時器
setInterval()
,計時器中呼叫的函式請使用箭頭函式,這樣被呼叫的函式裡的this
才會被正確的指向當前類,其它呼叫方法會指向window
componentDidMount() { setInterval(() => this.addNumber(),1000); }
-
定義你想呼叫的函式
注意!!!如果你想修改
state
中的值,請必須使用this.setState()
來修改!!addNumber(){ this.setState({ strike: this.state.strike + 100, }); }
-
最後,設定返回值,顯示的內容為
state
中的strike
值render(){ return (<h1>{this.state.strike}</h1>); }
-
-
加上點樣式
<script type="text/babel"> var container = document.querySelector("#container"); class Times extends React.Component{ constructor(props){ super(props); this.state = { strike: 0, }; } componentDidMount() { setInterval(() => this.addNumber(),1000); } addNumber(){ this.setState({ strike: this.state.strike + 100, }); } render(){ var strikeStyle = { margin: 0, padding: "55px", color: "#5dffff", fontSize: "60px", } return (<h1 style={strikeStyle}>{this.state.strike}</h1>); } }; class Words extends React.Component{ render(){ var words = { fontFamily: "sans-serif", margin: 0, padding: 0, }; var wordStyle = { wordNormal: { ...words, color: "#999999", fontSize: 33, }, wordBig: { ...words, color: "#999999", fontSize: 50, }, wordSmall: { ...words, color: "#4d4d4d", }, } return ( <div> <p style = {wordStyle.wordNormal}>lightning strike</p> <p style = {wordStyle.wordBig}>worldwide</p> <p style = {wordStyle.wordSmall}>(since you loaded this outstanding)</p> </div> ); } }; class BlackBoard extends React.Component{ render(){ return ( <div style = {this.props.style}> <Times/> <Words/> </div> ); } }; class Board extends React.Component{ render(){ var boardStyle = { board: { width: 300, height: 400, padding: 13, backgroundColor: "white", border: "2px solid black", }, blackboard: { height: "100%", backgroundColor: "black", borderRadius: "7%", textAlign: "center", lineHeight: "50px", } }; return ( <div style={boardStyle.board}> <BlackBoard style = {boardStyle.blackboard}/> </div> ); } }; ReactDOM.render( <Board/> ,container ); </script>
使用 JSX
即使我們在之前的文章中已經開始使用了 JSX
這種 React
特別的語法,但是,我們還是應該為它專門開闢一個新的章節,因為, JSX
、 元件 、 元件生命週期 是 React
的三大奠基核心(哈哈哈,當然是我的個人見解)。
說到 JSX
,令人印象深刻的就是各種在 js
裡新增 html
標籤 和出現在各個地方的 {}
在 js
裡新增 html
標籤
在提倡 css樣式 、 js行為 、 html標籤 分離的時代,這樣的設計別出心裁。主要是因為 React
的基礎設施不是傳統的 html標籤 ,而是各個 元件 。一個元件裡包含了構成頁面某一部分所需要的所有的 css樣式 、 js行為 、 html標籤 。 所以,遵循這樣的思路,在 js
裡新增 html
標籤 沒什麼稀奇的。
像這樣:
var myname = <h1>Batman</h1>;
function functionName(){ // your codes return <h1>Batman</h1>; }
const me = ( <div> <h1>Batman</h1> <h2>hello gotham</h2> </div> );
注意!!! JSX
不能夠將 多個html標籤 直接賦給一個變數或者直接返回,需要將 多個html標籤 包括在一個父元素中,就像上例第三個例子一樣。
{}
在 js
裡新增 html
標籤 對我們來說已經見怪不怪了,大括號 {}
的使用才是精髓。哈哈哈~~
{}
用於在 React
中的各個地方引用各種 合理的JS表示式(valid JavaScript expression) 。大括號裡可以是變數 user.username
、表示式 2+2
、函式呼叫 functionName(user)
等。
像這樣:
const name = 'Josh Perez'; const element = <h1>Hello, {name}</h1>;
const element = <img src={user.avatarUrl}></img>;
const element = <h1>2+2={2+2}</h1>;
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') );
另外,還有雙括號 {{}}
的寫法,這種表達方式用於在 JSX
裡內聯樣式。
{{}}
內的內容:
- 物件的寫法,將css裡的
;
變成,
- 屬性名使用駝峰寫法,css裡
-
後面的第一個字母大寫 -
只會生效最後一個
style
,下例中只會生效style={gothamStyle}
var myName = <h1 style={{color:"black"}} style={{fontSize:"25px"}} style={gothamStyle}>Batman</h1>;
像這樣:
const myName = <h1 style={{color:"black",fontSize:"25px"}}>Batman</h1>;
關於更多 React
中操作 CSS
,你還可以瀏覽這篇文章: https://www.jianshu.com/p/850...
JSX
的優勢
- 防止
XSS (cross-site-scripting)
攻擊。因為所有內容在被React
渲染到頁面上前都會先轉成字串 - 小巧靈活。
JSX
本質就是Javascript
,所以,JSX
可以被放在任何一個地方。再加上JSX
裡的內容非常豐富。結合React
的設計思想,JSX
非常好用。 - 當然
JSX
還可以撰寫css
內容,詳細可以參見之前章節:React
操作CSS
使用 JSX
的一個例子
只要使用 React
搭建網站必然需要用到 JSX
,額,雖然官方是這樣表示的:
Well~我們還是快速的過一遍這個例子
我們要實現的目標
幾個圓圈過1秒就變顏色,顏色隨機從顏色庫裡選取
完整程式碼
其實很簡單, Circle
元件負責改變顏色的行為, CreateCircle
元件負責定義樣式並渲染這些圓圈。
然後因為一直是動態的,所以,使用 Circle
元件的 state
,每個一段時間 setInterval
都會呼叫 changeColor
函式,來改變 state
裡的內容,改變之後 React
會重新渲染頁面被改動的部分。
值得注意的是,在這個例子中, JSX
被運用在任何一個位置,
-
可以被壓到陣列中去
colorarray.push(<CreateCircle bgColor={colors[random]} key={i}/>)
-
被渲染
render(){ return (<div>{this.state.colorArray}</div>); };
-
撰寫、引用
css
class CreateCircle extends React.Component{ render(){ var circleStyle = { padding: 10, margin: 20, display: "inline-block", backgroundColor: this.props.bgColor, borderRadius: "50%", width: 100, height: 100, }; return (<div style={circleStyle}></div>); } };
注意!!!在 React
中使用 key={}
屬性來唯一標識一個元件 <CreateCircle key={i}/>
完整程式碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Lightning</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.getElementById("container"); var colors = ["#393E41","#E94F37","#1C89BF","#A1D363","#85FFC7","#297373","#FF8552","#A40E4C"]; class Circle extends React.Component{ constructor(props){ super(props); this.state = { colorArray: [], }; }; changeColor(){ var colorarray = []; this.setState({ colorArray: [], }); for(var i=0;i < colors.length;i++){ var random = Math.floor(Math.random()*colors.length); colorarray.push(<CreateCircle bgColor={colors[random]} key={i}/>) this.setState({ colorArray: colorarray, }); } }; componentDidMount(){ setInterval(() => this.changeColor(),1000); }; render(){ return (<div>{this.state.colorArray}</div>); }; }; class CreateCircle extends React.Component{ render(){ var circleStyle = { padding: 10, margin: 20, display: "inline-block", backgroundColor: this.props.bgColor, borderRadius: "50%", width: 100, height: 100, }; return (<div style={circleStyle}></div>); } }; ReactDOM.render( <Circle/> ,container ) </script> </body> </html>
React
中的事件
事件的意義不用多說,事件是頁面與使用者互動的唯一途徑,人機互動大部分還是通過滑鼠和鍵盤吧,當然還有像手寫板、麥克風、攝像頭等裝置,但截至今日前端貌似沒有什麼許可權,不然安全性就太差了。
在 React
中,事件的繫結大致和原生網頁相似,大概也就是 命名方式不同 和 this
的指向不同 這兩點區別。
可以參考: https://reactjs.org/docs/hand...
在 React
中繫結事件
-
直接繫結
class Button extends React.Component{ render(){ return (<button onClick="console.log('Hello gotham')">Click me!</button>) } }
WHAT??這不是和原生的一模一樣嗎?是呀,只是在命名上採用的是
React
喜愛的 駝峰Camel-Case 命名法,原生的都是小寫。但這種方法多老式。 -
間接繫結
class Button extends React.Component{ consoleLog(){ console.log("Hello gotham"); } render(){ return (<button onClick={this.consoleLog}>Click me!</button>) } }
將函式拿到外面去,然後在元素的事件上繫結這個函式,繫結的時候使用
JSX
的{}
並且一定加上this
,表示繫結的是這個元件裡的函式。 -
超級間接繫結
class Inner extends React.Component{ render(){ return (<button onClick={this.props.clickHandler}>Click me!</button>) } } class Outer extends React.Component{ consoleLog(){ console.log("Hello gotham"); } render(){ return (<Inner clickHandler={this.consoleLog}/>) } }
哈哈哈,這是什麼鬼?就是利用了
React
的props
,把函式繫結在一個props
上,本例中是clickHandler
,然後渲染了新元件,在新元件中,可以使用this.props
來呼叫這個函式。簡單來說就是,將函式從 父元件 通過props
傳遞到了 子元件 。
this
的指向
在 React
中,絕大部分的 this
都指向元件本身。但是,在自定義的函式中, this
是沒有指向的,所以會有 this is undefined
的報錯,尤其是自定義的函式需要引用函式外元件內的其它資源的時候。
像下面這樣寫是會報錯的:
我們想要點選 Hello gotham
按鈕呼叫 greeting
函式, greeting
函式會呼叫 gotham
函式列印 Hello gotham
字樣。但是, greeting
函式裡的 this
沒有指向,所以會出現上面的報錯。
class Welcome extends React.Component{ gotham(){ console.log("Hello gotham"); } greeting(){ this.gotham(); } render(){ return (<button onClick={this.greeting}>Hello gotham<button/>) } }
所以,如果想要在自定義函式中呼叫同組件其它資源,你有下面3中方法來繫結 this
:
-
constructor
中繫結class Welcome extends React.Component{ constructor(props){ super(props); this.greeting = this.greeting.bind(this);:point_left:這句是繫結 } gotham(){ console.log("Hello gotham"); } greeting(){ this.gotham(); } render(){ return (<button onClick={this.greeting}>Hello gotham<button/>) } }
-
內聯式繫結
class Welcome extends React.Component{ gotham(){ console.log("Hello gotham"); } greeting(){ this.gotham(); } render(){ :point_down::point_down::point_down::point_down::point_down::point_down:這裡是繫結 return (<button onClick={this.greeting.bind(this)}>Hello gotham<button/>) } }
-
內聯式箭頭函式繫結
class Welcome extends React.Component{ gotham(){ console.log("Hello gotham"); } greeting(){ this.gotham(); } render(){ :point_down::point_down::point_down::point_down::point_down::point_down::point_down::point_down::point_down::point_down::point_down::point_down:這裡是繫結 return (<button onClick={(e) => this.greeting(e)}>Hello gotham<button/>) } }
關於繫結 this
還可以參考: https://www.jianshu.com/p/95a...
合成事件 SyntheticEvent
React
中的合成事件可以對應為通常函式中的事件物件 event
function gotham(event){ // your codes }
e...這個功能有點多,你可以自己打印出來看看呀,或者看看官方文件: https://reactjs.org/docs/even...
這裡只貼出來關於滑鼠和鍵盤事件:
-
滑鼠事件
booleanaltKey booleanctrlKey booleanshiftKey booleanmetaKey numberbutton numberbuttons numberclientX numberclientY booleangetModifierState(key) numberpageX numberpageY DOMEventTargetrelatedTarget numberscreenX numberscreenY
適用於如下事件:
onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp
-
鍵盤事件
booleanaltKey numbercharCode booleanctrlKey booleangetModifierState(key) stringkey numberkeyCode stringlocale numberlocation booleanmetaKey booleanrepeat booleanshiftKey numberwhich
適用於如下事件:
onKeyDown onKeyPress onKeyUp
關於事件的小例子
我們的目標
點選加號按鈕數字加1,按住shift點選加號,數字加10
實現思路
shift
拋開樣式的完整程式碼
其它的無關緊要,注意 Show
元件內的 increase
函式,我們可以看到 合成事件 e.shiftKey
和 {this.increase.bind(this)}
的使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>react-event</title> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> var container = document.querySelector("#container"); class Button extends React.Component{ render(){ return (<button onClick={this.props.clickHandler}>+</button>) } } class Show extends React.Component{ constructor(props){ super(props); this.state = { number: 0, }; } increase(e){ var num = this.state.number; if(e.shiftKey){ num += 10; }else{ num += 1; } this.setState({ number: num, }); } render(){ return ( <div> <p>{this.state.number}</p> <Button clickHandler={this.increase.bind(this)}/> </div> ) } } class Board extends React.Component{ render(){ return ( <div> <Show/> </div> ); } }; ReactDOM.render( <Board/>, container ) </script> </body> </html>
元件的生命週期 Lifecycle
React
創造出來元件,同時也給元件配上了生命週期,用來更好的控制組件,這也是 React
的一大優勢。
組建的生命週期可以參考這個: https://reactjs.org/docs/reac... 。往下多翻翻~~
這個參考資料也非常棒: https://www.w3cplus.com/react...
常用生命週期
componentDidMount() componentDidUpdate() componentWillUnmount()
不常用且慎用的生命週期
shouldComponentUpdate() static getDerivedStateFromProps() getSnapshotBeforeUpdate() static getDerivedStateFromError() componentDidCatch()
消失的生命週期
消失的生命週期不理他。
React Router
官方文件: https://reacttraining.com/rea...
github: https://github.com/ReactTrain...
React Router
就把他看作是一個外掛吧,中文名: React
路由 。