React學(xué)習(xí)(二)-深入淺出JSX

前言

在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);

其中ReactDOMreact-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)行斷言一下,就非常清晰這一過程了

image

image

所以歸納一下: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);

其中ReactDOMreact-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é)果如下所示


最終渲染結(jié)果.png

在編譯之后,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)行斷言一下,就非常清晰這一過程了

image

image

所以歸納一下: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ù)了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容