成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

重拾JSX

adam1q84 / 2633人閱讀

摘要:語法糖是一種的語法拓展,可以使用它來進(jìn)行的展示我們一般會(huì)在組件的方法里使用進(jìn)行布局和事件綁定的核心機(jī)制之一就是可以創(chuàng)建虛擬的元素,利用虛擬來減少對(duì)實(shí)際的操作從而提升性能,正是為了虛擬而存在的語法糖我們?cè)谄綍r(shí)的組件編寫中,通常都這么寫然而代碼

React.createElement語法糖

JSX是一種JavaScript的語法拓展,可以使用它來進(jìn)行UI的展示:

const element = 

Hello, world!

;

我們一般會(huì)在組件的render方法里使用JSX進(jìn)行布局和事件綁定:

class Home extends Component {
  render() {
    return (
      
console.log("hello")}>

Hello, world!

); } }

React的核心機(jī)制之一就是可以創(chuàng)建虛擬的DOM元素,利用虛擬DOM來減少對(duì)實(shí)際DOM的操作從而提升性能,JSX正是為了虛擬DOM而存在的語法糖

我們?cè)谄綍r(shí)的組件編寫中,通常都這么寫:

import React, { Component } from "react";

class Demo extends Component {
  render() {
    return (
      

Hello, world!

) } }

然而代碼里面并沒有用到React,為什么要引入這個(gè)變量呢?

因?yàn)镴SX是React.createElement這個(gè)方法的語法糖:

const element = 

Hello

; // 等價(jià)于 const element = React.createElement("h1", { id: "container", className: "home" }, "Hello");

推薦大家在babeljs.io上看下JSX編譯后的實(shí)際效果

React.createElement有三個(gè)參數(shù):

React.createElement(
  type, // dom類型,比如div,h1
  [props], // dom屬性,比如id,class,事件
  [...children] // 子節(jié)點(diǎn),字符串或者React.createElement生成的一個(gè)對(duì)象
)

JSX用一種類似HTML的語法替代了比較繁瑣的React.createElement純JS方法,而@babel/preset-react插件就起到了最關(guān)鍵的一步:負(fù)責(zé)在webpack編譯時(shí),把所有的JSX都改成React.createElement:

class Home extends Component {
  render() {
    return (
      
console.log("hello")}>

Hello, world!

); } }

編譯后:

class Home extends Component {
  render() {
    return React.createElement("div", {
      onClick: () => console.log("hello")
    }, React.createElement("h1", null, "Hello, world!"), React.createElement(Blog, {
      title: "deepred"
    }));
  }
}

在開發(fā)中,有了JSX后我們基本不怎么需要用到createElement方法,但如果我們需要實(shí)現(xiàn)這樣一個(gè)組件:

// 根據(jù)傳入的type屬性,渲染成相應(yīng)的html元素
 console.log("hello")}>this is a h1
this is a p

我們不太可能根據(jù)type的屬性,一個(gè)個(gè)if else去判斷對(duì)應(yīng)的標(biāo)簽:

function Tag(props) {
  const { type, ...other } = props;

  if (type === "h1") {
    return 

{props.children}

} if (type === "p") { return

{props.children}

} }

這時(shí),就需要用到底層的api了:

function Tag(props) {
  const { type, ...other } = props;

  return React.createElement(type, other, props.children);
}
自己實(shí)現(xiàn)一個(gè)JSX渲染器

虛擬dom本質(zhì)就是一個(gè)js對(duì)象:

const vnode = {
  tag: "div",
  attrs: {
    className: "container"
  },
  children: [
    {
        tag: "img",
        attrs: {
          src: "1.png"
        },
        children: []
    },
    {
        tag: "h3",
        attrs: {},
        children: ["hello"]
    }
  ]
}

可以通過在每個(gè)文件的上方添加/** @jsx h */來告訴@babel/preset-reacth方法名代替JSX(默認(rèn)方法是React.createElement)

/** @jsx h */

const element = 

Hello

;
/** @jsx h */
const element = h("h1", {
  id: "container",
  className: "home"
}, "Hello");

現(xiàn)在讓我們開始創(chuàng)建自己的h函數(shù)吧!

function h(nodeName, attributes, ...args) {
  // 使用concat是為了扁平化args,因?yàn)閍rgs數(shù)組里面的元素可能也是數(shù)組
  // h("div", {}, [1, 2, 3])  h("d", {}, 1, 2, 3) 都是合法的調(diào)用
  const children = args.length ? [].concat(...args) : null;

  return { nodeName, attributes, children };
}
const vnode = h("div", {
  id: "urusai"
}, "Hello!");

// 返回
// {
//  "nodeName": "div",
//  "attributes": {
//   "id": "urusai"
//  },
//  "children": [
//   "Hello!"
//  ]
// }

h的作用就是返回一個(gè)vnode,有了vnode,我們還需要把vnode轉(zhuǎn)成真實(shí)的dom:

function render(vnode) {
  if (typeof vnode === "string") {
    // 生成文本節(jié)點(diǎn)
    return document.createTextNode(vnode);
  }

  // 生成元素節(jié)點(diǎn)并設(shè)置屬性
  const node = document.createElement(vnode.nodeName);
  const attributes = vnode.attributes || {};
  Object.keys(attributes).forEach(key => node.setAttribute(key, attributes[key]));

  if (vnode.children) {
    // 遞歸調(diào)用render生成子節(jié)點(diǎn)
    vnode.children.forEach(child => node.appendChild(render(child)));
  }

  return node;
}

現(xiàn)在讓我們使用這兩個(gè)方法吧:

/** @jsx h */
const vnode = 
Hello!
; const node = render(vnode); document.body.appendChild(node);

編譯轉(zhuǎn)碼后:

/** @jsx h */
const vnode = h("div", {
  id: "urusai"
}, "Hello!");
const node = render(vnode);
document.body.appendChild(node);

我們還可以遍歷數(shù)組:

/** @jsx h */
const items = ["baga", "hentai", "urusai"];
const vnode = 
    {items.map((item, index) =>
  • {item}
  • )}
; const list = render(vnode); document.body.appendChild(list);

編譯轉(zhuǎn)碼后:

/** @jsx h */
const items = ["baga", "hentai", "urusai"];
const vnode = h("ul", null, items.map((item, index) => h("li", {
  key: index
}, item)));
const list = render(vnode);
document.body.appendChild(list);

通過h render兩個(gè)函數(shù),我們就實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的JSX渲染器?。?!

參考

WTF is JSX

JSX In Depth

React Without JSX

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/102716.html

相關(guān)文章

  • 重拾React: React 16.0

    摘要:然而之前的相當(dāng)于從最頂層的組件開始,自頂向下遞歸調(diào)用,不會(huì)被中斷,這樣就會(huì)持續(xù)占用瀏覽器主線程。眾所周知,是單線程運(yùn)行,長(zhǎng)時(shí)間占用主線程會(huì)阻塞其他類似于樣式計(jì)算布局繪制等運(yùn)算,從而出現(xiàn)掉幀的情況。 前言   首先歡迎大家關(guān)注我的Github博客,也算是對(duì)我的一點(diǎn)鼓勵(lì),畢竟寫東西沒法獲得變現(xiàn),能堅(jiān)持下去也是靠的是自己的熱情和大家的鼓勵(lì),希望大家多多關(guān)注呀!從今年年初離開React開發(fā)崗,...

    henry14 評(píng)論0 收藏0
  • 重拾css(1)——寫在前邊的話

    摘要:本系列文章重拾主要參考王福朋知多少,結(jié)合自己的理解和學(xué)習(xí)需要,修改或添加了一些內(nèi)容,難免有失偏頗,僅供自我學(xué)習(xí)參考之用。 工作中或多或少的寫一些css,但總感覺掌握的不夠扎實(shí),時(shí)而需要查閱一下知識(shí)點(diǎn)。我想,一方面跟缺少科班出身式的系統(tǒng)學(xué)習(xí)有關(guān),另一方面也苦于一直未尋覓到一套合我胃口教程。直到我讀到了王福朋css知多少系列文章,使我有了重新系統(tǒng)學(xué)習(xí)css的想法。 本系列文章(重拾css)...

    li21 評(píng)論0 收藏0
  • CSS魔法堂:重拾Border之——更廣闊的遐想

    摘要:也就是說我們操作的幾何公式中的未知變量,而具體的畫圖操作則由渲染引擎處理,而不是我們苦苦哀求設(shè)計(jì)師幫忙。 前言 ?當(dāng)CSS3推出border-radius屬性時(shí)我們是那么欣喜若狂啊,一想到終于不用再添加額外元素來模擬圓角了,但發(fā)現(xiàn)border-radius還分水平半徑和垂直半徑,然后又發(fā)現(xiàn)border-top-left/right-radius的水平半徑之和大于元素寬度時(shí),實(shí)際值會(huì)按比...

    lily_wang 評(píng)論0 收藏0
  • CSS魔法堂:重拾Border之——解構(gòu)Border

    摘要:本系列將稍微深入探討一下那個(gè)貌似沒什么好玩的魔法堂重拾之解構(gòu)魔法堂重拾之圖片作邊框魔法堂重拾之不僅僅是圓角魔法堂重拾之更廣闊的遐想解構(gòu)說起我們自然會(huì)想起,而由條緊緊包裹著的邊組成,所以的最小操作單元是。 前言 ?當(dāng)CSS3推出border-radius屬性時(shí)我們是那么欣喜若狂啊,一想到終于不用再添加額外元素來模擬圓角了,但發(fā)現(xiàn)border-radius還分水平半徑和垂直半徑,然后又發(fā)現(xiàn)...

    lingdududu 評(píng)論0 收藏0
  • 2017-08-08 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選一行代碼的逆向工程譯只需四個(gè)步驟使用實(shí)現(xiàn)頁面過渡動(dòng)畫如何實(shí)現(xiàn)一個(gè)基于的模板引擎解剖組件的多種寫法與演進(jìn)深入理解筆記擴(kuò)展對(duì)象的功能性中文基礎(chǔ)系列一之實(shí)現(xiàn)抽獎(jiǎng)刮刮卡橡皮擦掘金小游戲個(gè)人文章和最常用的特征眾成翻譯常用語法總 2017-08-08 前端日?qǐng)?bào) 精選 一行 JavaScript 代碼的逆向工程【譯】只需四個(gè)步驟:使用 React 實(shí)現(xiàn)頁面過渡動(dòng)畫如何實(shí)現(xiàn)一個(gè)基于 DOM...

    alin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<