前言
在Jq,原生javascript時(shí)期,在寫頁面時(shí),往往強(qiáng)調(diào)的是內(nèi)容結(jié)構(gòu),層疊樣式,行為動(dòng)作要分離,三者之間分工明確,不要耦合在一起
然而在React出現(xiàn)后,一切皆js,對(duì)于在JS里面寫HTML代碼,剛開始是非常反感的,甚至有違背當(dāng)初的原則
但是,對(duì)于原先那種僅僅是把三種語言技術(shù)放在了三種不同文件位置里進(jìn)行分開管理了,實(shí)際上,它并沒有實(shí)現(xiàn)邏輯上的分離
既然前端UI顯示就是HTML,CSS,javascript,那么把實(shí)現(xiàn)一個(gè)功能的所有代碼放在一個(gè)文件里管理,也是一種宏觀上代碼的封裝,模塊化處理.
使用JSX并不是倒退,它只是一個(gè)語法糖而已,雖然在React中,不強(qiáng)制要求使用JSX,但是官方卻推薦使用.
因?yàn)樵趈avascript代碼中將JSX和UI放在一起在視覺上有輔助作用,另外,它還可以使React顯示跟過有用的錯(cuò)誤和警告信息
下面就一起來學(xué)習(xí)下JSX吧,當(dāng)你習(xí)慣它之后呢,并不會(huì)嗤之以鼻,反而會(huì)引以為愛的
JSX是什么?
全稱: javascript and XML
定義: 可拓展(自定義)標(biāo)記性語言,基于javascript,融入了XML,我們可以在js中書寫xml,使用JSX可以很好的描述UI在頁面中應(yīng)該呈現(xiàn)它應(yīng)有的交互形式
類似下面的這種,非官方提供的普通標(biāo)簽,而是自己定義具有一定含義的特殊標(biāo)簽
<person>
<name></name>
<age></age>
<height></height>
<weight></weight>
</person>
其實(shí),你可把這些自定義的標(biāo)簽,稱為組件,頁面中的某一部分,具有獨(dú)立的功能和邏輯
實(shí)現(xiàn)組件化的好處,不言而喻,下面來看看React的JSX是怎么樣的
當(dāng)你用create-react-app腳手架,初始化一個(gè)react應(yīng)用后,在入口文件index.js中最后一行代碼,ReactDOM.render()函數(shù)調(diào)用的第一個(gè)實(shí)參數(shù)的寫法<App />
import React from 'react'; // 引入react.js庫,并用import關(guān)鍵字定義實(shí)例化了一個(gè)React對(duì)象
import ReactDOM from 'react-dom'; // 引入react-dom.js,同上,實(shí)例化了ReactDOM對(duì)象
ReactDOM.render(<App />, document.getElementById('root'))
為了更好的理解,你可以在index.js中,將代碼更改成如下
const element = <App />;
const container = documnent.getElementById("root");
ReactDOM.render(element, container);
其中ReactDOM是react-dom的一個(gè)實(shí)例對(duì)象,它是用來將虛擬dom轉(zhuǎn)換為真實(shí)DOM的,ReactDOM實(shí)例化對(duì)象下的一個(gè)render方法,接收兩個(gè)實(shí)際參數(shù),第一個(gè)實(shí)參數(shù),是要渲染的組件,第二個(gè)實(shí)參數(shù),是該組件的掛載點(diǎn),將組件渲染到什么位置上,這里是渲染到根節(jié)點(diǎn)root上
ReactDOM.render(要渲染的組件, 組件要掛載的位置);
其中類似這種JSX:
const element = <h1 title="h1標(biāo)簽">Hello,itclanCoder</h1>
// 等價(jià)于
var element = React.createElement('h1',{title:"h1標(biāo)簽"}, "hello, itclanCoder" );
// React.createElement() 會(huì)預(yù)先執(zhí)行一些檢查,以幫助你創(chuàng)建了這么一個(gè)對(duì)象,但是在實(shí)際中不要這么寫,它是會(huì)報(bào)錯(cuò)的
var element = {
type: 'h1',
props: {
title: "h1標(biāo)簽",
children: "hello,itclanCoder"
}
}
這些對(duì)象被稱為 “React 元素”。它們描述了你希望在屏幕上看到的內(nèi)容。React通過讀取這些對(duì)象,然后使用它們來構(gòu)建 DOM 以及保持隨時(shí)更新
注意:
React中并沒有模板語言(類似Vue的template的),但是它具有JavaScript的全部的功能
可以在JS中書寫XML(HTML) 只能有且僅有一個(gè)頂層元素 ,當(dāng)然也可以借助React提供的Fragment(也叫占位符)這個(gè)內(nèi)置組件將你寫的JSX子元素給包裹起來,可以包含子節(jié)點(diǎn) ,也支持插值表達(dá)式 {表達(dá)式}
為了便于閱讀,return返回的jsx內(nèi)容,用一個(gè)圓括號(hào)()包裹起來,這樣可以將JSX拆分為多行。這樣做不是強(qiáng)制要求的,但是這可以避免遇到自動(dòng)插入分號(hào)陷阱
如下代碼所示:
import React from "react";
import ReactDOM from "react-dom";
class Acomponent extends React.Component {
render() {
// return 后面帶著一個(gè)圓括號(hào),只是為了換行顯示,根節(jié)點(diǎn)最頂層只能是一個(gè)元素
return (
<div>
<h1 title="我是川川">一個(gè)靠前排的90后帥小伙</h1>
<h2>歡迎關(guān)注微信itclanCoder公眾號(hào)</h2>
</div>
)
}
}
// 或者使用React提供的Fragement占位符組件也可以,但是先引入
import React, { Componnet, Fragment } from "react";
import ReactDOM from "react-dom";
class Acomponent extends Component {
render() {
return (
<Fragment>
<h1 title="我是川川">一個(gè)靠前排的90后帥小伙</h1>
<h2>歡迎關(guān)注微信itclanCoder公眾號(hào)</h2>
</Fragment>
)
}
}
下面來具體來看看JSX是如何使用的
JSX的具體使用
- 在JSX中嵌入表達(dá)式{ 表達(dá)式 }
雙大括號(hào)內(nèi)可以是變量,字符串,數(shù)組,函數(shù)調(diào)用, 但是不可以是對(duì)象,也不支持 if,for語句
例如:你在插值表達(dá)式里寫對(duì)象:它是會(huì)報(bào)錯(cuò)的
{ {name: "川川", age: "一個(gè)靠前排的90后帥小伙"} }
錯(cuò)誤信息如下:
Objects are not valid as a React child (found: object with keys {name, age}). If you meant to render a collection of children, use an array instead
該錯(cuò)誤的意思是:對(duì)象無效作為React子對(duì)象(找到:具有鍵{name,age}的對(duì)象)。如果您要渲染子集合,請(qǐng)使用數(shù)組
當(dāng)然如果是數(shù)組的話,它會(huì)自動(dòng)的給拼接起來,本質(zhì)上是通過數(shù)組中的join("")方法處理后的結(jié)果
{ ["川川", "全宇宙最帥"]} //川川全宇宙最帥
當(dāng)然對(duì)于在JSX里面寫if,for語句也是會(huì)報(bào)錯(cuò)的
<li>
{
if(this.isBtn) { <Button />
}
</li>
其實(shí),JSX 也是一個(gè)表達(dá)式,它雖然不支持if,for語句,但是它在if,for循環(huán)的代碼塊中是可以使用JSX的,將JSX賦值給變量,把JSX當(dāng)作參數(shù)傳入,以及從函數(shù)中返回JSX
function getMessage(user) {
if (user) {
return <h1>Hello, { formatName(user) }!</h1>;
}
return <h1>Hello, itClanCoder.</h1>;
}`
注意:布爾類型、Null 以及 Undefined 將會(huì)被忽略,false, null, undefined, true是合法的子元素。但它們并不會(huì)被渲染。以下的 JSX 表達(dá)式渲染結(jié)果都是相同的:
<div />
<div></div>
<div>{ false }</div>
<div>{ null }</div>
<div>{ undefined }</div>
<div>{ true }</div>
具體作用: 這有助于在特定條件來渲染其他的 React 元素。例如,在以下 JSX 中,僅當(dāng) isBtn 為 true 時(shí),才會(huì)渲染<Button />
<div>
{ isBtn && <Button /> }
<Content />
</div>
有一點(diǎn)需要注意的是:有一些false值,例如:數(shù)字0,仍然會(huì)被React渲染,例如:如下所示
<div>
{
this.aBtns.length &&
<Button content="我是按鈕" />
}
</div>
要解決這個(gè)問題,確保 && 之前的表達(dá)式總是布爾值,就可以了
反之,如果你想渲染 false、true、null、undefined 等值,你需要先將它們轉(zhuǎn)換為字符串:
轉(zhuǎn)換字符串有如下三種方法
對(duì)象.toString(),注意此方法,針對(duì)數(shù)據(jù)類型是null對(duì)象,及undefined,不適用
用空字符串拼接:variable+'';此方法比較普遍,但是可讀性有些差
用String(variable):用String字符串對(duì)象方法進(jìn)行轉(zhuǎn)化,推薦使用
<div>
<p>對(duì)象.toString() { myVariable.toString() }</p>
<p>用空字符串拼接 { myVariable + '' }</p>
<p>用String(variable) { String(myVariable) }</p>
</div>
當(dāng)然,插值表達(dá)式中變量也可以用Es6中的反引號(hào)
hello, { `${String(false)}` } // false
介紹了那么多,依然還是不夠的,下面來看看JSX的原理,理解了這個(gè),你將會(huì)知道一個(gè)JSX究竟是怎么工作,以及怎么渲染到頁面上去的
JSX原理
頁面中的DOM元素結(jié)構(gòu)都可以用javascript對(duì)象來描述,包括的信息有,標(biāo)簽名,屬性,子元素,事件對(duì)象
在JS里面,一切皆對(duì)象,對(duì)象的特點(diǎn)就是,含有屬性或者方法,,其實(shí)任何東西,都可以用對(duì)象去描述
例如:如下的JSX結(jié)構(gòu)
<div class="input-wrap">
<input
type="text"
autocomplete="off"
value=""
id="mq"
class="input"
title="請(qǐng)輸入搜索文字" />
<button>搜索</button>
</div>
假如用對(duì)象來描述一下上面的信息:
{
tagName: 'div',
attribute: { className: 'input-wrap'},
children: [
{
tagName: 'input',
attribute: {
type: "text",
autocomplete:"off",
value:"",
id:"mq",
class:"input",
title:"請(qǐng)輸入搜索文字"
}
},
{
tagName: "button",
attribute: null,
children: '搜索'
}
]
}
當(dāng)直接把這個(gè)HTML段代碼寫在React中,它背后其實(shí)是通過React.createElement()方法進(jìn)行創(chuàng)建的,創(chuàng)建類似這樣的
{
type: 'div',
props: {className: 'input-wrap' },
children: [
{
type: 'input',
props: {
type:'text',
autocomplete:"off",
value:"",id:"mq",
class:"input",
title:"請(qǐng)輸入搜索文字"
},
{
type: 'button',
props: null,
children: '搜索'
}
]
}
你可以聯(lián)想一下原生javascript的document.createElement()與JQ中的$("")創(chuàng)建一個(gè)js對(duì)象與jQ對(duì)象的,而在React中,React就是一個(gè)實(shí)例化對(duì)象,更深層次探討的話,React也是基于原型對(duì)象構(gòu)建出來的
盡管React與前兩者不同,但是筆者仍然覺得有類似,異曲同工之妙,例如React下面的createElement方法,仍然與原生document文檔對(duì)象下面的創(chuàng)建元素方法相同
如果原生javascript扎實(shí)的話,便不難理解React在這做了一層轉(zhuǎn)化
既然js對(duì)象描述的UI(DOM)信息與HTML所展示的結(jié)構(gòu)信息是一樣的,那為什么不用Js對(duì)象來代替呢,因?yàn)橛脤?duì)象字面量寫的方式太繁瑣了,又臭又長(zhǎng)的,結(jié)構(gòu)又不清晰,如果用HTML來展示UI信息,那么就簡(jiǎn)單多了
React.js 就把js語法擴(kuò)展了一下,讓 Js語言能夠支持這種直接在Js代碼里面編寫類似 HTML 標(biāo)簽結(jié)構(gòu)的語法,這樣寫起來就方便很多了。編譯的過程會(huì)把類似 HTML 的 JSX 結(jié)構(gòu)轉(zhuǎn)換成 JavaScript 的對(duì)象結(jié)構(gòu)
上面的代碼:
import React from 'react'
import ReactDOM from 'react-dom'
class Search extends React.Component {
render () {
return (
<div class="input-wrap">
<input
type="text"
autocomplete="off"
value=""
id="mq"
class="input"
title="請(qǐng)輸入搜索文字" />
<button>搜索</button>
</div>
)
}
}
ReactDOM.render(
<Search />,
document.getElementById('root')
)
經(jīng)過babel編譯,Babel 會(huì)把 JSX 轉(zhuǎn)譯成一個(gè)名為 React.createElement() 函數(shù)調(diào)用,如下所示
import React from 'react'
import ReactDOM from 'react-dom'
class Search extends React.Component {
render () {
return (
React.createElement(
"div",
{className: 'input-wrap'},
React.createElement(
"input",
{ type:'text',
autocomplete:"off",
value:"",
id:"mq",
class:"input",
title:"請(qǐng)輸入搜索文字"
}
),
React.createElement(
'button',
null,
"搜索"
)
)
)
}
}
ReactDOM.render(
React.createElement(Search, null),
document.getElementById('root')
);
換言之,如果你自定義的一個(gè)組件:例如: <ElButton bgColor="green" />綠色按鈕</ElButton>
import React from 'react';
import ReactDOM from 'react-dom'
class ElButton extends React.Component {
constrcutor(props){
super(props);
}
render() {
return (
<button style={ {color: this.props.bgColor} }>{ this.props.children }</button>
)
}
}
ReactDOM.render(<ElButton bgColor="green">綠色按鈕</ElButton>, document.getElementById('root'));
經(jīng)過Babel的轉(zhuǎn)化后
React.createElement(
ElButton,
{ bgColor: green},
children: "綠色按鈕"
)
在編譯之后,JSX 表達(dá)式會(huì)被轉(zhuǎn)為普通 JavaScript 函數(shù)調(diào)用,并且對(duì)其取值后得到 JavaScript 對(duì)象
React.createELmenet會(huì)構(gòu)建一個(gè)js對(duì)象來描述你的HTML結(jié)構(gòu)信息,包括標(biāo)簽名,屬性,子元素以及事件對(duì)象等,使用React一定要引入React庫,引入這個(gè)是為了解析識(shí)別JSX語法糖(React.createElement()函數(shù)的替代)
當(dāng)然另一方面也是為了創(chuàng)建虛擬DOM(所謂虛擬DOM,它就是一個(gè)JS對(duì)象,是用它來描述真實(shí)的DOM,上面的例子,已經(jīng)很明白了),而引入react-dom的原因就是,為了將虛擬DOM轉(zhuǎn)換為真實(shí)DOM,然后把這個(gè)DOM元素插入到頁面中,這正是ReactDOM.render()做的事情,把組件渲染并且構(gòu)造 DOM 樹,然后插入到頁面上某個(gè)特定的元素上
所以在你編寫一個(gè)組件的時(shí)候,一開始就要引入兩個(gè)文件的
當(dāng)使用JSX到最終展現(xiàn)頁面結(jié)構(gòu)到瀏覽器上:經(jīng)歷了如下過程:如果你在代碼中進(jìn)行斷言一下,就非常清晰這一過程了
所以歸納一下:JSX其實(shí)就是javascript對(duì)象,是用來描述UI結(jié)構(gòu)信息的,JSX語法并不是真實(shí)的DOM, 使用JSX是為了方便開發(fā)人員寫代碼更簡(jiǎn)單,簡(jiǎn)潔
當(dāng)然實(shí)際開發(fā)中,我們并不會(huì)去用React.createElement()去創(chuàng)建元素,不是說它不能完成需求,只是因?yàn)樗鼘懫饋肀容^雞肋,代碼維護(hù)起來非常麻煩,可讀性差
相比于寫JS,寫HTML還是比較容易吧,但也是不簡(jiǎn)單的哦,因?yàn)閷慗S比較燒腦,容易掉頭發(fā)呀
然而,到手的人民幣的高低,更多的是取決于你的JS水平...,這個(gè)的確是滴,JS水平高,是可以直接喊高價(jià)的
小結(jié)
JSX 是 JavaScript 語言的一種語法擴(kuò)展,長(zhǎng)得像 HTML,但并不是 HTML,附加了原生HTML標(biāo)簽不具備的能力,例如:自定義屬性,以及后續(xù)的組件傳值
UI界面顯示什么樣,取決于JSX對(duì)象結(jié)構(gòu),換句話說,取決于render()函數(shù)里面的return關(guān)鍵字后面返回的JSX內(nèi)容結(jié)構(gòu)
引入React.js庫是為了解析識(shí)別JSX語法,同時(shí)創(chuàng)建虛擬DOM,而引入react-dom是為了渲染組件,將組件掛載到特定的位置上,同時(shí)將虛擬DOM轉(zhuǎn)換為真實(shí)DOM,插入到頁面中
總結(jié)
本文主要講述了JSX是什么?以及JSX的一些注意事項(xiàng),JSX的具體使用,嵌入表達(dá)式,最重要的是JSX的原理,在使用JSX中,react是如何將jsx語法糖裝換為真實(shí)DOM,并渲染到頁面中的,當(dāng)然,JSX仍然還有一些注意事項(xiàng),邊邊角角的知識(shí)的,限于篇幅,貪多嚼不爛,我們下次再繼續(xù)了
<person>
<age></age>
<name></name>
<height></height>
</person>
如下所示:當(dāng)你用create-react-app腳手架,初始化一個(gè)react應(yīng)用后,在入口文件index.js中最后一行代碼,ReactDOM.render()函數(shù)調(diào)用的第一個(gè)實(shí)參數(shù)的寫法<App />
import React from 'react'; // 引入react.js庫,并用import關(guān)鍵字定義實(shí)例化了一個(gè)React對(duì)象
import ReactDOM from 'react-dom'; // 引入react-dom.js,同上,實(shí)例化了ReactDOM對(duì)象
ReactDOM.render(<App />, document.getElementById('root'))
為了更好的理解,你可以在index.js中,將代碼更改成如下
const element = <App />;
const container = documnent.getElementById("root");
ReactDOM.render(element, container);
其中ReactDOM是react-dom的一個(gè)實(shí)例對(duì)象,它是用來將虛擬dom轉(zhuǎn)換為真實(shí)DOM的,ReactDOM實(shí)例化對(duì)象下的一個(gè)render方法,接收兩個(gè)實(shí)際參數(shù),第一個(gè)實(shí)參數(shù),是要渲染的組件,第二個(gè)實(shí)參數(shù),是該組件的掛載點(diǎn),將組件渲染到什么位置上,這里是渲染到根節(jié)點(diǎn)root上
ReactDOM.render(要渲染的組件, 組件要掛載的位置);
其中類似這種JSX:
const element = <h1 title="h1標(biāo)簽">Hello,itclanCoder</h1>
// 等價(jià)于
var element = React.createElement('h1',{title:"h1標(biāo)簽"}, "hello, itclanCoder" );
// React.createElement() 會(huì)預(yù)先執(zhí)行一些檢查,以幫助你創(chuàng)建了這么一個(gè)對(duì)象,但是在實(shí)際中不要這么寫,它是會(huì)報(bào)錯(cuò)的
var element = {
type: 'h1',
props: {
title: "h1標(biāo)簽",
children: "hello,itclanCoder"
}
}
這些對(duì)象被稱為 “React 元素”。它們描述了你希望在屏幕上看到的內(nèi)容。React通過讀取這些對(duì)象,然后使用它們來構(gòu)建 DOM 以及保持隨時(shí)更新
注意:
React中并沒有模板語言(類似Vue的template的),但是它具有JavaScript的全部的功能
可以在JS中書寫XML(HTML) 只能有且僅有一個(gè)頂層元素 ,當(dāng)然也可以借助React提供的Fragment(也叫占位符)這個(gè)內(nèi)置組件將你寫的JSX子元素給包裹起來,可以包含子節(jié)點(diǎn) ,也支持插值表達(dá)式 {表達(dá)式}
為了便于閱讀,return返回的jsx內(nèi)容,用一個(gè)圓括號(hào)()包裹起來,這樣可以將JSX拆分為多行。這樣做不是強(qiáng)制要求的,但是這可以避免遇到自動(dòng)插入分號(hào)陷阱
如下代碼所示:
import React from "react";
import ReactDOM from "react-dom";
class Acomponent extends React.Component {
render() {
// return 后面帶著一個(gè)圓括號(hào),只是為了換行顯示,根節(jié)點(diǎn)最頂層只能是一個(gè)元素
return (
<div>
<h1 title="我是川川">一個(gè)靠前排的90后帥小伙</h1>
<h2>歡迎關(guān)注微信itclanCoder公眾號(hào)</h2>
</div>
)
}
}
// 或者使用React提供的Fragement占位符組件也可以,但是先引入
import React, { Componnet, Fragment } from "react";
import ReactDOM from "react-dom";
class Acomponent extends Component {
render() {
return (
<Fragment>
<h1 title="我是川川">一個(gè)靠前排的90后帥小伙</h1>
<h2>歡迎關(guān)注微信itclanCoder公眾號(hào)</h2>
</Fragment>
)
}
}
下面來具體來看看JSX是如何使用的
JSX的具體使用
- 在JSX中嵌入表達(dá)式{ 表達(dá)式 }
雙大括號(hào)內(nèi)可以是變量,字符串,數(shù)組,函數(shù)調(diào)用, 但是不可以是對(duì)象,也不支持 if,for語句
例如:你在插值表達(dá)式里寫對(duì)象:它是會(huì)報(bào)錯(cuò)的
{ {name: "川川", age: "一個(gè)靠前排的90后帥小伙"} }
錯(cuò)誤信息如下:
Objects are not valid as a React child (found: object with keys {name, age}). If you meant to render a collection of children, use an array instead
該錯(cuò)誤的意思是:對(duì)象無效作為React子對(duì)象(找到:具有鍵{name,age}的對(duì)象)。如果您要渲染子集合,請(qǐng)使用數(shù)組
當(dāng)然如果是數(shù)組的話,它會(huì)自動(dòng)的給拼接起來,本質(zhì)上是通過數(shù)組中的join("")方法處理后的結(jié)果
{ ["川川", "全宇宙最帥"]} //川川全宇宙最帥
當(dāng)然對(duì)于在JSX里面寫if,for語句也是會(huì)報(bào)錯(cuò)的
<li>
{
if(this.isBtn) { <Button />
}
</li>
其實(shí),JSX 也是一個(gè)表達(dá)式,它雖然不支持if,for語句,但是它在if,for循環(huán)的代碼塊中是可以使用JSX的,將JSX賦值給變量,把JSX當(dāng)作參數(shù)傳入,以及從函數(shù)中返回JSX
function getMessage(user) {
if (user) {
return <h1>Hello, { formatName(user) }!</h1>;
}
return <h1>Hello, itClanCoder.</h1>;
}`
注意:布爾類型、Null 以及 Undefined 將會(huì)被忽略,false, null, undefined, true是合法的子元素。但它們并不會(huì)被渲染。以下的 JSX 表達(dá)式渲染結(jié)果都是相同的:
<div />
<div></div>
<div>{ false }</div>
<div>{ null }</div>
<div>{ undefined }</div>
<div>{ true }</div>
具體作用: 這有助于在特定條件來渲染其他的 React 元素。例如,在以下 JSX 中,僅當(dāng) isBtn 為 true 時(shí),才會(huì)渲染<Button />
<div>
{ isBtn && <Button /> }
<Content />
</div>
有一點(diǎn)需要注意的是:有一些false值,例如:數(shù)字0,仍然會(huì)被React渲染,例如:如下所示
<div>
{
this.aBtns.length &&
<Button content="我是按鈕" />
}
</div>
要解決這個(gè)問題,確保 && 之前的表達(dá)式總是布爾值,就可以了
反之,如果你想渲染 false、true、null、undefined 等值,你需要先將它們轉(zhuǎn)換為字符串:
轉(zhuǎn)換字符串有如下三種方法
對(duì)象.toString(),注意此方法,針對(duì)數(shù)據(jù)類型是null對(duì)象,及undefined,不適用
用空字符串拼接:variable+'';此方法比較普遍,但是可讀性有些差
用String(variable):用String字符串對(duì)象方法進(jìn)行轉(zhuǎn)化,推薦使用
<div>
<p>對(duì)象.toString() { myVariable.toString() }</p>
<p>用空字符串拼接 { myVariable + '' }</p>
<p>用String(variable) { String(myVariable) }</p>
</div>
當(dāng)然,插值表達(dá)式中變量也可以用Es6中的反引號(hào)
hello, { `${String(false)}` } // false
介紹了那么多,依然還是不夠的,下面來看看JSX的原理,理解了這個(gè),你將會(huì)知道一個(gè)JSX究竟是怎么工作,以及怎么渲染到頁面上去的
JSX原理
頁面中的DOM元素結(jié)構(gòu)都可以用javascript對(duì)象來描述,包括的信息有,標(biāo)簽名,屬性,子元素,事件對(duì)象
在JS里面,一切皆對(duì)象,對(duì)象的特點(diǎn)就是,含有屬性或者方法,,其實(shí)任何東西,都可以用對(duì)象去描述
例如:如下的JSX結(jié)構(gòu)
<div class="input-wrap">
<input
type="text"
autocomplete="off"
value=""
id="mq"
class="input"
title="請(qǐng)輸入搜索文字" />
<button>搜索</button>
</div>
假如用對(duì)象來描述一下上面的信息:
{
tagName: 'div',
attribute: { className: 'input-wrap'},
children: [
{
tagName: 'input',
attribute: {
type: "text",
autocomplete:"off",
value:"",
id:"mq",
class:"input",
title:"請(qǐng)輸入搜索文字"
}
},
{
tagName: "button",
attribute: null,
children: '搜索'
}
]
}
當(dāng)直接把這個(gè)HTML段代碼寫在React中,它背后其實(shí)是通過React.createElement()方法進(jìn)行創(chuàng)建的,創(chuàng)建類似這樣的
{
type: 'div',
props: {className: 'input-wrap' },
children: [
{
type: 'input',
props: {
type:'text',
autocomplete:"off",
value:"",id:"mq",
class:"input",
title:"請(qǐng)輸入搜索文字"
},
{
type: 'button',
props: null,
children: '搜索'
}
]
}
你可以聯(lián)想一下原生javascript的document.createElement()與JQ中的$("")創(chuàng)建一個(gè)js對(duì)象與jQ對(duì)象的,而在React中,React就是一個(gè)實(shí)例化對(duì)象,更深層次探討的話,React也是基于原型對(duì)象構(gòu)建出來的
盡管React與前兩者不同,但是筆者仍然覺得有類似,異曲同工之妙,例如React下面的createElement方法,仍然與原生document文檔對(duì)象下面的創(chuàng)建元素方法相同
如果原生javascript扎實(shí)的話,便不難理解React在這做了一層轉(zhuǎn)化
既然js對(duì)象描述的UI(DOM)信息與HTML所展示的結(jié)構(gòu)信息是一樣的,那為什么不用Js對(duì)象來代替呢,因?yàn)橛脤?duì)象字面量寫的方式太繁瑣了,又臭又長(zhǎng)的,結(jié)構(gòu)又不清晰,如果用HTML來展示UI信息,那么就簡(jiǎn)單多了
React.js 就把js語法擴(kuò)展了一下,讓 Js語言能夠支持這種直接在Js代碼里面編寫類似 HTML 標(biāo)簽結(jié)構(gòu)的語法,這樣寫起來就方便很多了。編譯的過程會(huì)把類似 HTML 的 JSX 結(jié)構(gòu)轉(zhuǎn)換成 JavaScript 的對(duì)象結(jié)構(gòu)
上面的代碼:
import React from 'react'
import ReactDOM from 'react-dom'
class Search extends React.Component {
render () {
return (
<div class="input-wrap">
<input
type="text"
autocomplete="off"
value=""
id="mq"
class="input"
title="請(qǐng)輸入搜索文字" />
<button>搜索</button>
</div>
)
}
}
ReactDOM.render(
<Search />,
document.getElementById('root')
)
經(jīng)過babel編譯以后會(huì)變成
import React from 'react'
import ReactDOM from 'react-dom'
class Search extends React.Component {
render () {
return (
React.createElement(
"div",
{className: 'input-wrap'},
React.createElement(
"input",
{ type:'text',
autocomplete:"off",
value:"",
id:"mq",
class:"input",
title:"請(qǐng)輸入搜索文字"
}
),
React.createElement(
'button',
null,
"搜索"
)
)
)
}
}
ReactDOM.render(
React.createElement(Search, null),
document.getElementById('root')
);
換言之,如果你自定義的一個(gè)組件:例如:<ElButton bgColor="green">綠色按鈕</ElButton>
import React from 'react';
import ReactDOM from 'react-dom'
class ElButton extends React.Component {
constructor(props){
super(props);
}
render() {
return (
<button
style={ {color: this.props.bgColor} }>{ this.props.children }</button>
)
}
}
經(jīng)過Babel的轉(zhuǎn)化后
React.createElement(
ElButton,
{ bgColor: green},
children: "綠色按鈕"
)
最終渲染到瀏覽器上,結(jié)果如下所示

在編譯之后,JSX 表達(dá)式會(huì)被轉(zhuǎn)為普通 JavaScript 函數(shù)調(diào)用,并且對(duì)其取值后得到 JavaScript 對(duì)象
React.createELmenet會(huì)構(gòu)建一個(gè)js對(duì)象來描述你的HTML結(jié)構(gòu)信息,包括標(biāo)簽名,屬性,子元素以及事件對(duì)象等,使用React一定要引入React庫,引入這個(gè)是為了解析識(shí)別JSX語法糖(React.createElement()函數(shù)的替代)
當(dāng)然另一方面也是為了創(chuàng)建虛擬DOM(所謂虛擬DOM,它就是一個(gè)JS對(duì)象,是用它來描述真實(shí)的DOM,上面的例子,已經(jīng)很明白了),而引入react-dom的原因就是,為了將虛擬DOM轉(zhuǎn)換為真實(shí)DOM,然后把這個(gè)DOM元素插入到頁面中,這正是ReactDOM.render()做的事情,把組件渲染并且構(gòu)造 DOM 樹,然后插入到頁面上某個(gè)特定的元素上
所以在你編寫一個(gè)組件的時(shí)候,一開始就要引入兩個(gè)文件的
當(dāng)使用JSX到最終展現(xiàn)頁面結(jié)構(gòu)到瀏覽器上:經(jīng)歷了如下過程:如果你在代碼中進(jìn)行斷言一下,就非常清晰這一過程了
所以歸納一下:JSX其實(shí)就是javascript對(duì)象,是用來描述UI結(jié)構(gòu)信息的,JSX語法并不是真實(shí)的DOM, 使用JSX是為了方便開發(fā)人員寫代碼更簡(jiǎn)單,簡(jiǎn)潔
當(dāng)然實(shí)際開發(fā)中,我們并不會(huì)去用React.createElement()去創(chuàng)建元素,不是說它不能完成需求,只是因?yàn)樗鼘懫饋肀容^雞肋,代碼維護(hù)起來非常麻煩,可讀性差
相比于寫JS,寫HTML還是比較容易吧,但也是不簡(jiǎn)單的哦,因?yàn)閷慗S比較燒腦,容易掉頭發(fā)呀
然而,到手的人民幣的高低,更多的是取決于你的JS水平...,這個(gè)的確是滴,JS水平高,是可以直接喊高價(jià)的
小結(jié)
JSX 是 JavaScript 語言的一種語法擴(kuò)展,長(zhǎng)得像 HTML,但并不是 HTML,附加了原生HTML標(biāo)簽不具備的能力,例如:自定義屬性,以及后續(xù)的組件傳值
UI界面顯示什么樣,取決于JSX對(duì)象結(jié)構(gòu),換句話說,取決于render()函數(shù)里面的return關(guān)鍵字后面返回的JSX內(nèi)容結(jié)構(gòu)
引入React.js庫是為了解析識(shí)別JSX語法,同時(shí)創(chuàng)建虛擬DOM,而引入react-dom是為了渲染組件,將組件掛載到特定的位置上,同時(shí)將虛擬DOM轉(zhuǎn)換為真實(shí)DOM,插入到頁面中
總結(jié)
本文主要講述了JSX是什么?以及JSX的一些注意事項(xiàng),JSX的具體使用,嵌入表達(dá)式,最重要的是JSX的原理,在使用JSX中,react是如何將jsx語法糖裝換為真實(shí)DOM,并渲染到頁面中的,當(dāng)然,JSX仍然還有一些注意事項(xiàng),邊邊角角的知識(shí)的,限于篇幅,貪多嚼不爛,我們下次再繼續(xù)了