flutter web

翻譯:https://medium.com/flutter-io/hummingbird-building-flutter-for-the-web-e687c2a023a8

在今天的Flutter Live上冈绊,我們宣布我們正在嘗試在網(wǎng)上運(yùn)行Flutter刽虹。在這篇文章中国夜,我們描述了我們?nèi)绾螒?yīng)對挑戰(zhàn)以及技術(shù)的當(dāng)前狀態(tài)威始。在帖子的最后,您將找到有關(guān)互操作和嵌入的問題的答案肤寝。

讓我們快速回顧一下Flutter的架構(gòu)当辐。Flutter是一個(gè)多層系統(tǒng),這樣更高的層更容易使用鲤看,并允許您用很少的代碼表達(dá)很多缘揪,而較低的層為您提供更多的控制,代價(jià)是必須處理一些復(fù)雜性。當(dāng)較高層不能滿足開發(fā)人員的需求時(shí)找筝,它們可以降到較低層蹈垢。開發(fā)人員可以訪問Flutter Engine上方的所有層。

Flutter Engine作為Flutter中最低級別的庫暴露袖裕,dart:ui耘婚。它對小部件,物理陆赋,動(dòng)畫或布局(文本布局除外)一無所知。它所知道的是如何將圖片組合到屏幕上并將它們變成像素嚷闭。在dart:ui上直接編寫應(yīng)用程序是很困難的攒岛。這就是創(chuàng)建更高層的原因。

以上所有事情:ui是我們所謂的“框架”胞锰。它下面的一切都是“引擎”灾锯。該框架完全使用Dart編程語言編寫。大多數(shù)引擎都是用C ++編寫的嗅榕,特定于Android的部分用Java編寫顺饮,而iOS特定的部分用Objective-C編寫。dart中的一些基本類和函數(shù):ui是用Dart編寫的凌那,主要用作Dart和C ++之間的橋梁兼雄。

Flutter還提供插件系統(tǒng)。插件是用一種語言編寫的代碼帽蝶,可以直接訪問移動(dòng)生態(tài)系統(tǒng)隨著時(shí)間累積的OEM庫和第三方庫赦肋。要為Android創(chuàng)建插件,您可以編寫Java或Kotlin励稳。iOS插件是使用Objective-C或Swift編寫的佃乘。

你好,網(wǎng)絡(luò)

Web平臺已經(jīng)發(fā)展了數(shù)十年驹尼,包括許多技術(shù)和規(guī)范趣避。有一些總括性術(shù)語用于描述大量相關(guān)功能:HTML,CSS新翎,SVG程帕,JavaScript,WebGL地啰。為了在Web上運(yùn)行Flutter骆捧,我們需要:

  • 編譯Dart代碼: Flutter是用Dart編寫的,我們需要在Web上運(yùn)行Dart髓绽。
  • 選擇要在Web上運(yùn)行的Flutter子集在Web上運(yùn)行所有Flutter代碼是不實(shí)際或有用的敛苇。其中一些是特定于平臺的,例如Android和iOS位。
  • 選擇足夠的Web功能子集:隨著時(shí)間的推移枫攀,Web平臺會累積功能重疊的功能括饶。例如,您可以使用HTML + CSS来涨,SVG图焰,Canvas和WebGL繪制圖形。

只要語言存在蹦掐,Dart就一直在編譯JavaScript技羔。許多重要的應(yīng)用程序從Dart編譯為JavaScript,并在今天的生產(chǎn)中運(yùn)行卧抗。Flutter的編譯策略依賴于同樣的基礎(chǔ)設(shè)施藤滥。

當(dāng)我們開始探索時(shí),我們面臨著UI渲染的幾種選擇社裆。我們很快意識到我們想要支持的特定Flutter層決定了我們將用于實(shí)現(xiàn)的Web技術(shù)拙绊。我們制作了三個(gè)原型

  1. 只是小部件:這個(gè)原型實(shí)現(xiàn)了Flutter的小部件框架,并提供了一組核心布局小部件作為構(gòu)建自定義小部件的基礎(chǔ)泳秀。對于布局和定位标沪,它依賴于Web的內(nèi)置功能,例如flexbox嗜傅,網(wǎng)格布局金句,瀏覽器滾動(dòng)瀏覽overflow:scroll等。
  2. 小部件+自定義布局:此原型包括Flutter的布局系統(tǒng)(由提供RenderObject)吕嘀,但將渲染對象直接映射到HTML元素趴梢。
  3. Flutter Web Engine:這個(gè)原型保留了dart:ui之上的所有層,并提供了一個(gè)在瀏覽器中運(yùn)行的dart:ui實(shí)現(xiàn)币他。

Flutter最有價(jià)值的功能之一是它可以跨平臺移植坞靶。雖然您可以(有時(shí)甚至鼓勵(lì))編寫自定義平臺特定代碼,但可以共享跨平臺不需要不同的代碼蝴悉。這允許使用單個(gè)代碼庫編寫面向多個(gè)平臺的應(yīng)用程序彰阴。

在嘗試將幾個(gè)示例應(yīng)用程序移植到Web之后,我們意識到原型#1和#2不能提供Flutter開發(fā)人員喜歡的可移植性級別拍冠。因此尿这,我們決定使用Flutter Web Engine設(shè)計(jì)的原型#3,因?yàn)檫@將允許平臺之間最高的框架級代碼重用:

現(xiàn)在我們知道我們想要實(shí)現(xiàn)整個(gè)dart:ui API庆杜,我們需要選擇一組Web技術(shù)來構(gòu)建射众。Flutter一次呈現(xiàn)一幀UI。在每個(gè)框架內(nèi)晃财,F(xiàn)lutter 構(gòu)建小部件叨橱,執(zhí)行布局,最后在屏幕上繪制它們。

構(gòu)建小部件

窗口小部件構(gòu)建機(jī)制不依賴于應(yīng)用程序運(yùn)行的環(huán)境罗洗。該過程只是實(shí)例化內(nèi)存中的對象愉舔,跟蹤它們的狀態(tài),以及狀態(tài)更改何時(shí)計(jì)算系統(tǒng)的較低級別伙菜,布局和繪制所需的最小更新轩缤。將此部分移植到Web上非常簡單。在Dart團(tuán)隊(duì)在dart2js中實(shí)現(xiàn)了super-mixin支持后贩绕,編譯器將所有小部件和小部件框架編譯為JavaScript火的,幾乎沒有任何問題。

布局

布局系統(tǒng)有點(diǎn)棘手淑倾。最大的挑戰(zhàn)是文本布局馏鹤。其他所有內(nèi)容 - 中心,行踊淳,列,堆棧陕靠,可滾動(dòng)迂尝,填充,換行等 - 由框架布局剪芥,因此無需修改即可編譯到Web垄开。

在Flutter中,您可以通過創(chuàng)建Paragraph對象并調(diào)用其layout()方法來布置一段文本税肪。不幸的是溉躲,Web缺少直接的文本布局API。我們用來測量文本布局屬性的技巧是讓瀏覽器將其布局益兄,然后從DOM元素中讀回相關(guān)屬性锻梳。

在布置一段文本時(shí),F(xiàn)lutter測量段落的高度净捅,寬度疑枯,最大內(nèi)在寬度,最小內(nèi)在寬度以及字母和表意基線蛔六。這些屬性如下所示荆永。

您可以在Flutter的段落文檔中找到更多詳細(xì)信息。

要測量這些屬性国章,我們首先在HTML DOM元素中放置一個(gè)段落具钥,然后我們讀取元素的維度。這會導(dǎo)致瀏覽器將其布局液兽。例如骂删,要獲取元素的寬度和高度,我們調(diào)用offsetWidth及其兄弟offsetHeight。為了測量基線桃漾,我們將段落放置在一個(gè)元素中坏匪,該元素被配置為使用flex行進(jìn)行自我布局。在段落旁邊撬统,我們放置另一個(gè)名為“probe”的元素适滓。因?yàn)樘结樑c文本的基線對齊,所以調(diào)用getBoundingClientRect就可以得到基線恋追。我們使用類似的技巧來測量最小和最大內(nèi)在寬度凭迹。

繪畫

最后但并非最不重要的是,我們需要繪制小部件苦囱。這個(gè)區(qū)域在我們的探索中經(jīng)歷了最多的流失嗅绸,它仍然是我們研究中最活躍的領(lǐng)域之一。在框架結(jié)束時(shí)撕彤,我們所有的小部件都需要在屏幕上變成像素鱼鸠。在瀏覽器中,這意味著它們必須歸結(jié)為HTML / CSS羹铅,Canvas蚀狰,SVG和WebGL的某種組合。

我們還沒有看過WebGL职员,主要是因?yàn)樗堑图墑e的并且要求我們重新實(shí)現(xiàn)瀏覽器已經(jīng)可以做的事情麻蹋,例如文本布局和光柵化2D圖形,還因?yàn)槲覀冞€沒有弄清楚可訪問性焊切,文本選擇扮授,使用非Flutter組件的組合可以與WebGL一起使用。

我們的早期原型之一為每個(gè)RenderObject生成了一個(gè)HTML元素专肪。我們確實(shí)獲得了有希望的結(jié)果刹勃,但結(jié)果證明API變化太大了。我們必須用Flutter維持一個(gè)巨大的代碼增量嚎尤,所以我們擱置了這個(gè)想法深夯。

我們目前正在同時(shí)探索兩種方法:

  • HTML + CSS +帆布
  • CSS Paint API

HTML + CSS +帆布

通過這種方法,我們將框架生成的圖片分類為使用HTML + CSS表達(dá)的圖片诺苹,以及使用Canvas 2D表達(dá)的圖片咕晋。然后,我們輸出結(jié)合了HTML收奔,CSS和2D畫布的HTML DOM掌呜。

我們更喜歡HTML + CSS,因?yàn)樗蔀g覽器的顯示列表支持坪哄。這意味著我們可以優(yōu)化圖片的光柵化到瀏覽器的渲染引擎质蕉。這也意味著我們可以應(yīng)用任意變換势篡,尤其是旋轉(zhuǎn)和縮放,而不必?fù)?dān)心像素化模暗。我們將此畫布實(shí)現(xiàn)稱為DomCanvas禁悠。

如果我們無法使用HTML + CSS表達(dá)圖片,我們會回到畫布兑宇。Canvas 2D允許我們繪制幾乎所有的Flutter繪圖命令碍侦。如果您將Flutter的Canvas與Web的CanvasRenderingContext2D進(jìn)行比較,您會發(fā)現(xiàn)許多相似之處隶糕。在畫布上繪畫是有效的瓷产,因?yàn)樗粫?chuàng)建需要隨時(shí)間維護(hù)的可變樹節(jié)點(diǎn),如HTML DOM或SVG枚驻。

2D畫布的一個(gè)挑戰(zhàn)是瀏覽器將其表示為位圖濒旦,即存儲寬度 x 高度像素的內(nèi)存緩沖區(qū)。因此再登,縮放畫布會導(dǎo)致像素化尔邓。如果縮放導(dǎo)致調(diào)整圖片大小,我們需要調(diào)整畫布大小锉矢。我們發(fā)現(xiàn)分配畫布相當(dāng)昂貴梯嗽,因此調(diào)整它們的大小。最重要的是沈撞,當(dāng)將多個(gè)畫布合成到同一頁面上時(shí)慷荔,瀏覽器必須執(zhí)行柵格合成雕什,這也會顯示在我們的配置文件中缠俺。合成柵格與顯示列表的工作方式不同。您可以將多個(gè)顯示列表繪制到同一個(gè)內(nèi)存緩沖區(qū)中贷岸。我們調(diào)用Canvas 2D支持的canvas實(shí)現(xiàn)BitmapCanvas壹士。我們正在研究使位圖畫布更有效的方法。

為了表達(dá)Flutter的不透明度偿警,變換躏救,偏移,剪輯矩形和其他圖層螟蒸,我們使用純HTML元素盒使。例如,不透明層變?yōu)?code><flt-opacity>具有opacityCSS屬性的元素七嫌,變換層變?yōu)?code><flt-transform>具有transformCSS屬性的元素少办,剪輯rect變?yōu)?code><flt-clip-rect>with overflow: hidden

完成所有操作后诵原,框架將作為HTML元素樹呈現(xiàn)在頁面上英妓,其中DomCanvas和BitmapCanvas作為葉節(jié)點(diǎn)挽放。例如:
Flutter Engine中的等效Flutter層樹(稱為流層)如下所示:

在結(jié)構(gòu)上它們非常相似。最大的區(qū)別是蔓纠,在Web上辑畦,我們必須根據(jù)內(nèi)容選擇不同的圖片實(shí)現(xiàn)。

HTML + CSS + Canvas適用于所有現(xiàn)代瀏覽器腿倚。但是纯出,我們已經(jīng)在展望未來:

CSS Paint API

CSS Paint是一個(gè)新的Web API,是Houdini的一個(gè)更大的努力的一部分猴誊。Houdini是許多瀏覽器供應(yīng)商之間的合作潦刃,旨在向開發(fā)人員公開CSS引擎的某些部分。特別是懈叹,CSS Paint API允許開發(fā)人員在這些元素請求繪制時(shí)將自定義圖形繪制成HTML元素乖杠。例如,您可以將元素的繪制分配給background自定義CSS畫家澄成。它與canvas非常相似胧洒,但有以下重要區(qū)別:

  • 這個(gè)繪畫不是由主要的JavaScript獨(dú)立完成的,而是由一個(gè)叫做paint worklet的東西完成的墨状。它有點(diǎn)像Web工作者卫漫,因?yàn)樗凶约旱膬?nèi)存空間。在提交DOM更改之后肾砂,在瀏覽器的繪制階段執(zhí)行繪制工作列赎。
  • CSS繪制由顯示列表支持,而不是位圖镐确。這為我們提供了兩全其美 - 2D畫布般的繪畫效率無像素化包吝。
  • 目前CSS繪畫不支持繪畫文本。

在撰寫本文時(shí)源葫,Chrome和Opera是唯一支持CSS Paint生產(chǎn)的瀏覽器诗越。但是,其他瀏覽器處于運(yùn)送其實(shí)現(xiàn)的各個(gè)階段息堂。

我們在Flutter for Web中對CSS Paint API進(jìn)行了實(shí)驗(yàn)性支持嚷狞,它已經(jīng)顯示出良好的結(jié)果,特別是在性能方面荣堰。我們的實(shí)現(xiàn)只是將paint命令序列化為自定義CSS屬性床未。paint worklet讀取這些命令并執(zhí)行它們。我們使用普通<p><span>HTML元素渲染文本振坚。

我們當(dāng)前的序列化機(jī)制不是特別有效 - 它是一個(gè)嵌套列表轉(zhuǎn)換為JSON的樹 - 但Houdini項(xiàng)目的一部分是添加對類型化數(shù)組的支持薇搁。當(dāng)它變得可用時(shí),我們將繪制命令編碼為類型化數(shù)組而不是JSON字符串屡拨。類型化數(shù)組是可轉(zhuǎn)換的只酥,這意味著它們可以通過引用從主隔離區(qū)傳遞到繪制工作區(qū)褥实。不涉及復(fù)制內(nèi)存。

互操作和嵌入

從Flutter調(diào)用Dart庫

Flutter Web應(yīng)用程序可以完全訪問當(dāng)今在Web上運(yùn)行的所有現(xiàn)有Dart庫裂允。

從Flutter調(diào)用JavaScript庫

Flutter Web應(yīng)用程序完全支持Dart的JS-interop軟件包:package:jsdart:js损离。

在Flutter Web應(yīng)用程序中使用CSS

目前,F(xiàn)lutter假設(shè)完全控制網(wǎng)頁的正確性和性能绝编。例如僻澎,我們只使用遵循某些性能指南的一小部分CSS,例如https://csstriggers.com/十饥。在頁面上放置任意CSS可能會導(dǎo)致Flutter表現(xiàn)不可預(yù)測窟勃。

在Flutter for Web應(yīng)用程序中避免使用CSS的另一個(gè)原因是,在設(shè)計(jì)時(shí)逗堵,F(xiàn)lutter需要在呈現(xiàn)框架時(shí)知道所有布局屬性秉氧。CSS充當(dāng)黑盒子。例如蜒秤,如果要顯示可滾動(dòng)的窗口小部件列表绅络,則必須實(shí)例化并為所有窗口小部件生成HTML并應(yīng)用必要的CSS屬性(例如列牺,flex-direction row和overflow:scroll)。然后瀏覽器將所有內(nèi)容都放出并將其呈現(xiàn)為屏幕作喘。應(yīng)用程序代碼不參與布局過程灭袁。

最后尸红,本著保持Flutter代碼可跨平臺移植的精神绩郎,我們避免使用CSS蔼水,因此我們可以在Android和iOS上本機(jī)運(yùn)行相同的代碼。

將Flutter嵌入現(xiàn)有的Web應(yīng)用程序中

我們尚未為此添加適當(dāng)?shù)闹С峙遥覀兇蛩阍趯磉M(jìn)行探索蚤假。我們正在考慮的幾種方法是<iframe>影子DOM。

在Flutter中嵌入非Flutter組件

我們尚未添加對在Flutter Web應(yīng)用程序中嵌入非Flutter組件(自定義元素田绑,React組件勤哗,Angular組件)的支持抡爹,但我們打算在將來探討這一點(diǎn)掩驱。一種可能的途徑是使用平臺視圖將外來內(nèi)容放入Flutter Web應(yīng)用程序中。需要考慮的一個(gè)重要方面是外國內(nèi)容可能對應(yīng)用程序的性能和正確性產(chǎn)生何種影響冬竟。因?yàn)榉荈lutter組件可能包含任意CSS欧穴,如上所述,它可能會有問題泵殴。需要更多的研究涮帘。

可移植性

我們的目標(biāo)是盡可能多地將框架移植到Web上。但是笑诅,這并不意味著任何Flutter應(yīng)用程序?qū)⒃赪eb上運(yùn)行而不會更改代碼调缨。Flutter網(wǎng)絡(luò)應(yīng)用程序仍然是一個(gè)Web應(yīng)用程序; 它在瀏覽器中被沙箱化疮鲫,只能執(zhí)行Web瀏覽器允許的操作。例如弦叶,如果您的Flutter應(yīng)用程序使用沒有Web實(shí)現(xiàn)的本機(jī)插件(例如ARCore)俊犯,您將無法在Web上運(yùn)行該應(yīng)用程序。同樣伤哺,沒有直接訪問文件系統(tǒng)或低級網(wǎng)絡(luò)的權(quán)限燕侠。

當(dāng)前狀態(tài)

我們構(gòu)建了足夠的Web引擎來渲染大部分的Flutter Gallery。我們還沒有移植Cupertino小部件立莉,但所有Material小部件绢彤,Material Theming,以及Shrine和Contact Profile演示應(yīng)用程序都在Web上運(yùn)行蜓耻。

https://youtu.be/5IrPi2Eo-xM

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茫舶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刹淌,更是在濱河造成了極大的恐慌奇适,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芦鳍,死亡現(xiàn)場離奇詭異嚷往,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)柠衅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門皮仁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人菲宴,你說我怎么就攤上這事贷祈。” “怎么了喝峦?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵势誊,是天一觀的道長。 經(jīng)常有香客問我谣蠢,道長粟耻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任眉踱,我火速辦了婚禮挤忙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谈喳。我一直安慰自己册烈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布婿禽。 她就那樣靜靜地躺著赏僧,像睡著了一般大猛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淀零,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天胎署,我揣著相機(jī)與錄音,去河邊找鬼窑滞。 笑死琼牧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哀卫。 我是一名探鬼主播巨坊,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼此改!你這毒婦竟也來了趾撵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤共啃,失蹤者是張志新(化名)和其女友劉穎占调,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體移剪,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡究珊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纵苛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剿涮。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖攻人,靈堂內(nèi)的尸體忽然破棺而出取试,到底是詐尸還是另有隱情,我是刑警寧澤怀吻,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布瞬浓,位于F島的核電站,受9級特大地震影響蓬坡,放射性物質(zhì)發(fā)生泄漏猿棉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一渣窜、第九天 我趴在偏房一處隱蔽的房頂上張望铺根。 院中可真熱鬧宪躯,春花似錦乔宿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掂林。三九已至坝橡,卻和暖如春泻帮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背计寇。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工番宁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝶押,地道東北人棋电。 一個(gè)月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓企锌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親于未。 傳聞我的和親對象是個(gè)殘疾皇子霎俩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 譯者丨覃云 Flutter 是什么打却? Flutter 移動(dòng)應(yīng)用程序 SDK 是為開發(fā)人員提供一種創(chuàng)建快捷、美觀的應(yīng)...
    言射手閱讀 7,816評論 1 14
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案谎倔? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,751評論 1 92
  • 國慶后面兩天在家學(xué)習(xí)整理了一波flutter柳击,基本把能擼過能看到的代碼都過了一遍,此文篇幅較長片习,建議保存(star...
    Nealyang閱讀 4,343評論 1 17
  • 目錄 一捌肴、Flutter 為何使用Dart開發(fā)語言二、Flutter的UI系統(tǒng)1.特點(diǎn)2.架構(gòu)簡介2.1 Flut...
    十拿九穩(wěn)啦閱讀 3,660評論 3 28
  • 湖光粼粼小船搖 寧靜和諧水中漂 老翁布網(wǎng)抖魚兒 魚兒不覺只顧躍 人生至樂莫如此 鮮花掌聲皆可拋 建功立業(yè)多迷茫 不...
    神于天圣于地閱讀 318評論 0 1