中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何讓小程序支持JSX語法

發布時間:2022-03-17 10:14:46 來源:億速云 閱讀:437 作者:iii 欄目:web開發

今天小編給大家分享一下如何讓小程序支持JSX語法的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

現有思路的局限

在介紹新的思路之前,我們先來看下Taro(最新版1.3),nanachi是怎么在小程序端處理JSX語法的。簡單來說,主要是通過在編譯階段把JSX轉化為等效的小程序wxml來把React代碼運行在小程序端的。

舉個例子,比如React邏輯表達式:

xx && <Text>Hello</Text>

將會被轉化為等效的小程序wx:if指令:

<Text wx:if="{{xx}}">Hello</Text>

這種方式把對JSX的處理,主要放在了編譯階段,他依賴于編譯階段的信息收集,以上面為例,它必須識別出邏輯表達式,然后做對應的wx:if轉換處理。

那編譯階段有什么問題和局限呢?我們以下面的例子說明:

class App extends React.Component {

    render () {

        const a = <Text>Hello</Text>

        const b = a

        return (

            <View>

                {b}

            </View>

        )

    }

}

首先我們聲明 const a = <Text>Hello</Text>,然后把a賦值給了b,我們看下最新版本Taro 1.3的轉換,如下圖:

這個例子不是特別復雜,卻報錯了。

要想理解上面的代碼為什么報錯,我們首先要理解編譯階段。本質上來說在編譯階段,代碼其實就是&lsquo;字符串&rsquo;,而編譯階段處理方案,就需要從這個&lsquo;字符串&rsquo;中分析出必要的信息(通過AST,正則等方式)然后做對應的等效轉換處理。

而對于上面的例子,需要做什么等效處理呢?需要我們在編譯階段分析出b是JSX片段:b = a = <Text>Hello</Text>,然后把<View>{b}</View>中的{b}等效替換為<Text>Hello</Text>。然而在編譯階段要想確定b的值是很困難的,有人說可以往前追溯來確定b的值,也不是不可以,但是考慮一下 由于b = a,那么就先要確定a的值,這個a的值怎么確定呢?需要在b可以訪問到的作用域鏈中確定a,然而a可能又是由其他變量賦值而來,循環往復,期間一旦出現不是簡單賦值的情況,比如函數調用,三元判斷等運行時信息,追溯就宣告失敗,要是a本身就是掛在全局對象上的變量,追溯就更加無從談起。

所以在編譯階段 是無法簡單確定b的值的。

我們再仔細看下上圖的報錯信息:a is not defined。

為什么說a未定義呢?這是涉及到另外一個問題,我們知道<Text>Hello</Text>,其實等效于React.createElement(Text, null, 'Hello'),而React.createElement方法的返回值就是一個普通JS對象,形如

// ReactElement對象

{

   tag: Text,

   props: null,

   children: 'Hello'

   ...

}

所以上面那一段代碼在JS環境真正運行的時候,大概等效如下:

class App extends React.Component {

    render () {

        const a = {

            tag: Text,

            props: null,

            children: 'Hello'

            ...

        }

        const b = a

        return {

            tag: View,

            props: null,

            children: b

            ...

        }

    }

}

但是,我們剛說了編譯階段需要對JSX做等效處理,需要把JSX轉換為wxml,所以<Text>Hello</Text>這個JSX片段被特殊處理了,a不再是一個普通js對象,這里我們看到a變量甚至丟失了,這里暴露了一個很嚴重的問題:代碼語義被破壞了,也就是說由于編譯時方案對JSX的特殊處理,真正運行在小程序上的代碼語義并不是你的預期。這個是比較頭疼。

新的思路

正因為編譯時方案,有如上的限制,在使用的時候常常讓你有“我還是在寫React嗎?”這種感覺。

下面我們介紹一種全新的處理思路,這種思路在小程序運行期間和真正的React幾無區別,不會改變任何代碼語義,JSX表達式只會被處理為React.createElement方法調用,實際運行的時候就是普通js對象,最終通過其他方式渲染出小程序視圖。下面我們仔細說明一下這個思路的具體內容。

第一步:給每個獨立的JSX片段打上唯一標識uuid,假定我們有如下代碼:

const a = <Text uuid="000001">Hello</Text>

const y = <View uuid="000002">

    <Image/>

    <Text/>

</View>

我們給a片段,y片段 添加了uuid屬性

第二步:把React代碼通過babel轉義為小程序可以識別的代碼,例如JSX片段用等效的React.createElement替換等

const a = React.createElement(Text, {

  uuid: "000001"

}, "Hello");

第三步:提取每個獨立的JSX片段,用小程序template包裹,生成wxml文件

<template name="000001">

    <Text>Hello</Text>

</template>

<template name="000002">

    <View uuid="000002">

        <Image/>

        <Text/>

    </View>

</template>

<!--占位template-->

<template is="{{uiDes.name}}" data="{{...uiDes}}"/>

注意這里每一個template 的name標識和 JSX片段的唯一標識uuid是一樣的。最后,需要在結尾生成一個占位模版:<template is="{{uiDes.name}}" data="{{...uiDes}}"/>。

第四步:修改ReactDOM.render的遞歸(React 16.x之后,不在是遞歸的方式)過程,遞歸執行階段,聚合JSX片段的uuid屬性,生成并返回uiDes數據結構。

第五步:把第四步生成的uiDes,傳遞給小程序環境,小程序把uiDes 設置給占位模版<template is="{{uiDes.name}}" data="{{...uiDes}}"/>,渲染出最終的視圖。

我們以上面的App組件的例子來說明整個過程,首先js代碼會被轉義為:

class App extends React.Component {

    render () {

        const a = React.createElement(Text, {uuid: "000001"}, "Hello");

        const b = a

        return (

          React.createElement(View, {uuid: "000002"} , b);

        )

      }

}

同時生成wxml文件:

<template name="000001">

    <Text>Hello</Text>

</template>

<template name="000002">

    <View>

        <template is="{{child0001.name}}" data="{{...child0001}}"/>

    </View>

</template>

<!--占位template-->

<template is="{{uiDes.name}}" data="{{...uiDes}}"/>

使用我們定制之后render執行ReactDOM.render(<App/>, parent)。在render的遞歸過程中,除了會執行常規的創建組件實例,執行生命周期之外,還會額外的收集執行過程中組件的uuid標識,最終生成 uiDes 對象

const uiDes = {

    name: "000002",

    child0001: {

        name: 000001,

        ...

   }

   ...

}

小程序獲取到這個uiDes,設置給占位模版<template is="{{uiDes.name}}" data="{{...uiDes}}"/>。 最終渲染出小程序視圖。

在這整個過程中,你的所有JS代碼都是運行在React過程中的,語義完全一致,JSX片段也不會被任何特殊處理,只是簡單的React.createElement調用,另外由于這里的React過程只是純js運算,執行是非常迅速的,通常只有幾ms。最終會輸出一個uiDes數據到小程序,小程序通過這個uiDes渲染出視圖。

現在我們在看之前的賦值const b = a,就不會有任何問題了,因為a 不過是普通對象。另外對于常見的編譯時方案的限制,比如任意函數返回JSX片段,動態生成JSX片段,for循環使用JSX片段等等,都可以完全解除了,因為JSX片段只是js對象,你可以做任何操作,最終ReactDOM.render會搜集所有執行結果的片段的uuid標識,生成uiDes,而小程序會根據這個uiDes數據結構渲染出最終視圖。

可以看出這種新的思路和以前編譯時方案還是有很大的區別的,對JSX片段的處理是動態的,你可以在任何地方,任何函數出現任何JSX片段, 最終執行結果會確定渲染哪一個片段,只有執行結果的片段的uuid會被寫入uiDes。這和編譯時方案的靜態識別有著本質的區別。

以上就是“如何讓小程序支持JSX語法”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

嘉定区| 太谷县| 万年县| 大埔区| 仪陇县| 简阳市| 万安县| 佛教| 罗定市| 连江县| 河间市| 西峡县| 股票| 长丰县| 南宫市| 河南省| 万州区| 嘉禾县| 广元市| 斗六市| 恩平市| 遂昌县| 黄浦区| 波密县| 达州市| 靖西县| 黄冈市| 平顶山市| 五莲县| 连江县| 高清| 嘉禾县| 姜堰市| 潞西市| 三门峡市| 漳州市| 海兴县| 潮安县| 巍山| 泰州市| 民丰县|