網頁總是一個鏈接着另一個的,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}/> //👈👈使用擴展運算符進行簡化{...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); 👈這句是綁定 } 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(){ 👇👇👇👇👇👇這裏是綁定 return (<button onClick={this.greeting.bind(this)}>Hello gotham<button/>) } }
-
內聯式箭頭函數綁定
class Welcome extends React.Component{ gotham(){ console.log("Hello gotham"); } greeting(){ this.gotham(); } render(){ 👇👇👇👇👇👇👇👇👇👇👇👇這裏是綁定 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...
這裏只貼出來關於鼠標和鍵盤事件:
-
鼠標事件
boolean altKey boolean ctrlKey boolean shiftKey boolean metaKey number button number buttons number clientX number clientY boolean getModifierState(key) number pageX number pageY DOMEventTarget relatedTarget number screenX number screenY
適用於如下事件:
onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp
-
鍵盤事件
boolean altKey number charCode boolean ctrlKey boolean getModifierState(key) string key number keyCode string locale number location boolean metaKey boolean repeat boolean shiftKey number which
適用於如下事件:
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
路由。