亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 課堂 > 小程序 > 正文

淺談一種讓小程序支持JSX語法的新思路

2020-03-21 15:53:55
字體:
來源:轉載
供稿:網友

React社區一直在探尋使用React語法開發小程序的方式,其中比較著名的項目有Taro,nanachi。而使用React語法開發小程序的難點主要就是在JSX語法上,JSX本質上是JS,相比于小程序靜態模版來說太靈活。本文所說的新思路就是在處理JSX語法上的新思路,這是一種更加動態的處理思路,相比于現有方案,基本上不會限制任何JSX的寫法,讓你以真正的React方式處理小程序,希望這個新思路可以給任何有志于用React開發小程序的人帶來啟發。

現有思路的局限

在介紹新的思路之前,我們先來看下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>              </View>    )  }}

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

小程序,JSX語法

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

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

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

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

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

小程序,JSX語法

為什么說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}}"/>。 最終渲染出小程序視圖。

小程序,JSX語法

在這整個過程中,你的所有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。這和編譯時方案的靜態識別有著本質的區別。

結語

"Talk is cheap. Show me your code!" 這僅僅是一個思路?還是已經有落地完整的實現呢?

是有完整的實現的,alita項目在處理JSX語法的時候,采用的就是這個思路,這也是alita基本不限制寫法卻可以轉化整個React Native項目的原因,另外alita在這個思路上做了很多優化。如果對這個思路的具體實現有興趣,可以去研讀一下alita源碼,它完全是開源的https://github.com/areslabs/alita。

當然,你也可以基于這個思路,構造出自己的React小程序開發方案。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
中日韩美女免费视频网站在线观看| 日韩高清a**址| 大荫蒂欧美视频另类xxxx| 欧美在线亚洲一区| 在线观看国产成人av片| 一本色道久久88综合亚洲精品ⅰ| 亚洲精品ady| 国产91在线播放精品91| 精品精品国产国产自在线| 亚洲福利在线播放| 国产成人涩涩涩视频在线观看| 亚洲午夜av电影| 国产在线高清精品| 久久精品这里热有精品| 在线视频日韩精品| 日产精品久久久一区二区福利| 精品在线小视频| 欧美丰满老妇厨房牲生活| 国产精品丝袜白浆摸在线| 日韩免费看的电影电视剧大全| 久久亚洲精品视频| 欧美老女人bb| 久久久99免费视频| 91美女福利视频高清| 亚州国产精品久久久| 亚洲男人天堂九九视频| 成人精品一区二区三区电影免费| 中文国产成人精品| 不卡av电影在线观看| 亚洲精品欧美一区二区三区| 亚洲国产成人久久综合一区| 欧美激情一二三| 亚洲精品国产欧美| 中文字幕亚洲激情| 国产精品久久久久久久av大片| 亚洲欧美国产一区二区三区| 青草青草久热精品视频在线观看| 最近2019中文字幕大全第二页| 亚洲白虎美女被爆操| 久久久久免费精品国产| 疯狂做受xxxx欧美肥白少妇| 欧美精品一本久久男人的天堂| 欧美一二三视频| 91久久夜色精品国产网站| 隔壁老王国产在线精品| 亚洲欧美日韩中文在线制服| 成人激情视频在线| 日本精品视频在线观看| 久久久精品2019中文字幕神马| 国产精品高潮呻吟久久av无限| 亚洲一区二区久久久久久久| 亚洲香蕉成视频在线观看| 日韩在线视频导航| 亚洲xxxx妇黄裸体| 国内精品视频一区| 国产精品入口尤物| 久久夜色撩人精品| 国产精品一区二区三区毛片淫片| 日韩欧美国产成人| 日韩欧美国产一区二区| 久久影院资源站| 日韩精品在线视频| 国产精品视频午夜| 中文字幕日韩欧美精品在线观看| 亚洲国产精品人人爽夜夜爽| 精品一区二区三区四区在线| 色香阁99久久精品久久久| 午夜精品三级视频福利| 国产999精品久久久影片官网| 国产日韩欧美自拍| 亚洲女人被黑人巨大进入al| 欧美日韩精品在线视频| 精品久久久久久国产91| 日韩亚洲精品视频| 国产精品久久久久久久久久免费| 91高清视频在线免费观看| 成人福利网站在线观看| 国产乱肥老妇国产一区二| 在线播放精品一区二区三区| 大量国产精品视频| 欧美丝袜第一区| 亚洲国产中文字幕在线观看| 日韩欧美国产黄色| 精品国产一区二区三区久久狼黑人| 成人免费视频xnxx.com| 成人免费在线视频网址| 日韩电影在线观看永久视频免费网站| 欧美日韩爱爱视频| 欧美视频二区36p| 亚洲尤物视频网| 亚洲高清久久网| 欧美极品少妇与黑人| 国产精品27p| 91成人在线播放| 国产精品精品国产| 欧美一区第一页| 亚洲精品一区二区三区婷婷月| 国产精品羞羞答答| 91精品久久久久久久久中文字幕| 久久的精品视频| 中文字幕免费精品一区高清| 久久精品中文字幕免费mv| 最近中文字幕mv在线一区二区三区四区| 亚洲深夜福利在线| 成人精品久久一区二区三区| 国产v综合ⅴ日韩v欧美大片| 国模极品一区二区三区| 国产精品久久久久久久久久小说| 久久av在线播放| 97av在线影院| 亚洲国产精品国自产拍av秋霞| 国产成人精彩在线视频九色| 亚洲第一区第二区| 一区二区三区高清国产| 亚洲国产精品字幕| 精品久久久久久久久久久| 亚洲美女黄色片| 亚洲欧美激情四射在线日| 九九热这里只有精品免费看| 日韩精品久久久久久福利| 国模视频一区二区三区| 国产一区二区av| 国产亚洲精品综合一区91| 精品自拍视频在线观看| 久久久精品久久久久| 韩剧1988在线观看免费完整版| 欧美肥老妇视频| 欧美性xxxx极品hd欧美风情| 午夜精品国产精品大乳美女| 欧美网站在线观看| 欧美日韩国产精品一区二区不卡中文| 久久久精品国产一区二区| xxxxx91麻豆| 精品视频www| 色偷偷9999www| 国产精品麻豆va在线播放| 成人自拍性视频| 一区二区三欧美| 国产精品精品久久久| 欧美乱大交做爰xxxⅹ性3| 国产成人精品电影| 久久久久久国产精品美女| 中文字幕精品www乱入免费视频| 亚洲在线免费观看| 亚洲色图综合久久| 亚洲网在线观看| 久久69精品久久久久久国产越南| 成人免费网站在线看| 97视频免费在线看| 欧美精品在线观看91| 日韩欧美有码在线| 韩国三级日本三级少妇99| 日韩极品精品视频免费观看| 国产精品久久77777| 川上优av一区二区线观看| 国产精品亚发布| 美日韩精品免费视频| 亚洲国产精品推荐| 国内精品久久久久影院优| 欧美视频在线看| 国产日本欧美一区| 欧美日韩中文字幕在线| 色悠久久久久综合先锋影音下载| 亚洲国产精品久久精品怡红院|