成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Android徹底組件化方案實(shí)踐

移動(dòng)開(kāi)發(fā) Android
項(xiàng)目發(fā)展到一定程度,隨著人員的增多,代碼越來(lái)越臃腫,這時(shí)候就必須進(jìn)行模塊化的拆分。在我看來(lái),模塊化是一種指導(dǎo)理念,其核心思想就是分而治之、降低耦合。而在 Android 工程中如何實(shí)施,目前有兩種途徑,也是兩大流派,一個(gè)是組件化,一個(gè)是插件化。

一、模塊化、組件化與插件化

項(xiàng)目發(fā)展到一定程度,隨著人員的增多,代碼越來(lái)越臃腫,這時(shí)候就必須進(jìn)行模塊化的拆分。在我看來(lái),模塊化是一種指導(dǎo)理念,其核心思想就是分而治之、降低耦合。而在 Android 工程中如何實(shí)施,目前有兩種途徑,也是兩大流派,一個(gè)是組件化,一個(gè)是插件化。

提起組件化和插件化的區(qū)別,有一個(gè)很形象的圖:

 

 

 

 

上面的圖看上去比較清晰,其實(shí)容易導(dǎo)致一些誤解,有下面幾個(gè)小問(wèn)題,圖中可能說(shuō)的不太清楚:

組件化是一個(gè)整體嗎?去了頭和胳膊還能存在嗎?左圖中,似乎組件化是一個(gè)有機(jī)的整體,需要所有器官都健在才可以存在。而實(shí)際上組件化的目標(biāo)之一就是降低整體(app)與器官(組件)的依賴關(guān)系,缺少任何一個(gè)器官 app 都是可以存在并正常運(yùn)行的。

頭和胳膊可以單獨(dú)存在嗎?左圖也沒(méi)有說(shuō)明白,其實(shí)答案應(yīng)該是肯定的。每個(gè)器官(組件)可以在補(bǔ)足一些基本功能之后都是可以獨(dú)立存活的。這個(gè)是組件化的第二個(gè)目標(biāo):組件可以單獨(dú)運(yùn)行。

組件化和插件化可以都用右圖來(lái)表示嗎?如果上面兩個(gè)問(wèn)題的答案都是 YES 的話,這個(gè)問(wèn)題的答案自然也是 YES。每個(gè)組件都可以看成一個(gè)單獨(dú)的整體,可以按需的和其他組件(包括主項(xiàng)目)整合在一起,從而完成的形成一個(gè) app。

右圖中的小機(jī)器人可以動(dòng)態(tài)的添加和修改嗎?如果組件化和插件化都用右圖來(lái)表示,那么這個(gè)問(wèn)題的答案就不一樣了。對(duì)于組件化來(lái)講,這個(gè)問(wèn)題的答案是部分可以,也就是在編譯期可以動(dòng)態(tài)的添加和修改,但是在運(yùn)行時(shí)就沒(méi)法這么做了。而對(duì)于插件化,這個(gè)問(wèn)題的答案很干脆,那就是完全可以,不論實(shí)在編譯期還是運(yùn)行時(shí)!

本文主要集中講的是組件化的實(shí)現(xiàn)思路,對(duì)于插件化的技術(shù)細(xì)節(jié)不做討論,我們只是從上面的問(wèn)答中總結(jié)出一個(gè)結(jié)論:組件化和插件化的***區(qū)別(應(yīng)該也是唯一區(qū)別)就是組件化在運(yùn)行時(shí)不具備動(dòng)態(tài)添加和修改組件的功能,但是插件化是可以的。

暫且拋棄對(duì)插件化“道德”上的批判,我認(rèn)為對(duì)于一個(gè) Android 開(kāi)發(fā)者來(lái)講,插件化的確是一個(gè)福音,這將使我們具備極大的靈活性。但是苦于目前還沒(méi)有一個(gè)完全合適、***兼容的插件化方案(RePlugin 的饑餓營(yíng)銷做的很好,但還沒(méi)看到療效),特別是對(duì)于已經(jīng)有幾十萬(wàn)代碼量的一個(gè)成熟產(chǎn)品來(lái)講,套用任何一個(gè)插件化方案都是很危險(xiǎn)的工作。所以我們決定先從組件化做起,本著做一個(gè)最徹底的組件化方案的思路去進(jìn)行代碼的重構(gòu),下面是最近的思考結(jié)果,歡迎大家提出建議和意見(jiàn)。

二、如何實(shí)現(xiàn)組件化

要實(shí)現(xiàn)組件化,不論采用什么樣的技術(shù)路徑,需要考慮的問(wèn)題主要包括下面幾個(gè):

  • 代碼解耦。如何將一個(gè)龐大的工程拆分成有機(jī)的整體?
  • 組件單獨(dú)運(yùn)行。上面也講到了,每個(gè)組件都是一個(gè)完整的整體,如何讓其單獨(dú)運(yùn)行和調(diào)試呢?
  • 數(shù)據(jù)傳遞。因?yàn)槊總€(gè)組件都會(huì)給其他組件提供的服務(wù),那么主項(xiàng)目(Host)與組件、組件與組件之間如何傳遞數(shù)據(jù)?
  • UI 跳轉(zhuǎn)。UI 跳轉(zhuǎn)可以認(rèn)為是一種特殊的數(shù)據(jù)傳遞,在實(shí)現(xiàn)思路上有啥不同?
  • 組件的生命周期。我們的目標(biāo)是可以做到對(duì)組件可以按需、動(dòng)態(tài)的使用,因此就會(huì)涉及到組件加載、卸載和降維的生命周期。
  • 集成調(diào)試。在開(kāi)發(fā)階段如何做到按需的編譯組件?一次調(diào)試中可能只有一兩個(gè)組件參與集成,這樣編譯的時(shí)間就會(huì)大大降低,提高開(kāi)發(fā)效率。
  • 代碼隔離。組件之間的交互如果還是直接引用的話,那么組件之間根本沒(méi)有做到解耦,如何從根本上避免組件之間的直接引用呢?也就是如何從根本上杜絕耦合的產(chǎn)生呢?只有做到這一點(diǎn)才是徹底的組件化。

2.1 代碼解耦

把龐大的代碼進(jìn)行拆分,Androidstudio 能夠提供很好的支持,使用 IDE 中的 multiple module 這個(gè)功能,我們很容易把代碼進(jìn)行初步的拆分。在這里我們對(duì)兩種 module 進(jìn)行區(qū)分:

  • 一種是基礎(chǔ)庫(kù) library,這些代碼被其他組件直接引用。比如網(wǎng)絡(luò)庫(kù) module 可以認(rèn)為是一個(gè) library。
  • 另一種我們稱之為 Component,這種 module 是一個(gè)完整的功能模塊。比如讀書(shū)或者分享 module 就是一個(gè) Component。

為了方便,我們統(tǒng)一把 library 稱之為依賴庫(kù),而把 Component 稱之為組件,我們所講的組件化也主要是針對(duì) Component 這種類型。而負(fù)責(zé)拼裝這些組件以形成一個(gè)完成 app 的 module,一般我們稱之為主項(xiàng)目、主 module 或者 Host,方便起見(jiàn)我們也統(tǒng)一稱為主項(xiàng)目。

經(jīng)過(guò)簡(jiǎn)單的思考,我們可能就可以把代碼拆分成下面的結(jié)構(gòu):

 

 

組件化簡(jiǎn)單拆分

 

 

這種拆分都是比較容易做到的,從圖上看,讀書(shū)、分享等都已經(jīng)拆分組件,并共同依賴于公共的依賴庫(kù)(簡(jiǎn)單起見(jiàn)只畫(huà)了一個(gè)),然后這些組件都被主項(xiàng)目所引用。讀書(shū)、分享等組件之間沒(méi)有直接的聯(lián)系,我們可以認(rèn)為已經(jīng)做到了組件之間的解耦。但是這個(gè)圖有幾個(gè)問(wèn)題需要指出:

  • 從上面的圖中,我們似乎可以認(rèn)為組件只有集成到主項(xiàng)目才可以使用,而實(shí)際上我們的希望是每個(gè)組件是個(gè)整體,可以獨(dú)立運(yùn)行和調(diào)試,那么如何做到單獨(dú)的調(diào)試呢?
  • 主項(xiàng)目可以直接引用組件嗎?也就是說(shuō)我們可以直接使用 compile project(:reader) 這種方式來(lái)引用組件嗎?如果是這樣的話,那么主項(xiàng)目和組件之間的耦合就沒(méi)有消除啊。我們上面講,組件是可以動(dòng)態(tài)管理的,如果我們刪掉 reader(讀書(shū))這個(gè)組件,那么主項(xiàng)目就不能編譯了啊,談何動(dòng)態(tài)管理呢?所以主項(xiàng)目對(duì)組件的直接引用是不可以的,但是我們的讀書(shū)組件最終是要打到 apk 里面,不僅代碼要和并到 claases.dex 里面,資源也要經(jīng)過(guò) meage 操作合并到 apk 的資源里面,怎么避免這個(gè)矛盾呢?
  • 組件與組件之間真的沒(méi)有相互引用或者交互嗎?讀書(shū)組件也會(huì)調(diào)用分享模塊啊,而這在圖中根本沒(méi)有體現(xiàn)出來(lái)啊,那么組件與組件之間怎么交互呢?

這些問(wèn)題我們后面一個(gè)個(gè)來(lái)解決,首先我們先看代碼解耦要做到什么效果,像上面的直接引用并使用其中的類肯定是不行的了。所以我們認(rèn)為代碼解耦的首要目標(biāo)就是組件之間的完全隔離,我們不僅不能直接使用其他組件中的類,***能根本不了解其中的實(shí)現(xiàn)細(xì)節(jié)。只有這種程度的解耦才是我們需要的。

2.2 組件的單獨(dú)調(diào)試

其實(shí)單獨(dú)調(diào)試比較簡(jiǎn)單,只需要把 apply plugin: 'com.android.library'切換成 apply plugin: 'com.android.application'就可以,但是我們還需要修改一下 AndroidManifest 文件,因?yàn)橐粋€(gè)單獨(dú)調(diào)試需要有一個(gè)入口的 actiivity。

我們可以設(shè)置一個(gè)變量 isRunAlone,標(biāo)記當(dāng)前是否需要單獨(dú)調(diào)試,根據(jù) isRunAlone 的取值,使用不同的 gradle 插件和 AndroidManifest 文件,甚至可以添加 Application 等 Java 文件,以便可以做一下初始化的操作。

為了避免不同組件之間資源名重復(fù),在每個(gè)組件的 build.gradle 中增加 resourcePrefix "xxx_",從而固定每個(gè)組件的資源前綴。下面是讀書(shū)組件的 build.gradle 的示例:

  1. if(isRunAlone.toBoolean()){     
  2. apply plugin: 'com.android.application' 
  3. }else{   
  4. apply plugin: 'com.android.library' 
  5. ..... 
  6.   resourcePrefix "readerbook_" 
  7.   sourceSets { 
  8.       main { 
  9.           if (isRunAlone.toBoolean()) { 
  10.               manifest.srcFile 'src/main/runalone/AndroidManifest.xml' 
  11.               java.srcDirs = ['src/main/java','src/main/runalone/java'
  12.               res.srcDirs = ['src/main/res','src/main/runalone/res'
  13.           } else { 
  14.               manifest.srcFile 'src/main/AndroidManifest.xml' 
  15.           } 
  16.       } 
  17.   } 

 

通過(guò)這些額外的代碼,我們給組件搭建了一個(gè)測(cè)試 Host,從而讓組件的代碼運(yùn)行在其中,所以我們可以再優(yōu)化一下我們上面的框架圖。

 

 

支持單獨(dú)調(diào)試的組件化

 

 

2.3 組件的數(shù)據(jù)傳輸

上面我們講到,主項(xiàng)目和組件、組件與組件之間不能直接使用類的相互引用來(lái)進(jìn)行數(shù)據(jù)交互。那么如何做到這個(gè)隔離呢?在這里我們采用接口 + 實(shí)現(xiàn)的結(jié)構(gòu)。每個(gè)組件聲明自己提供的服務(wù) Service,這些 Service 都是一些抽象類或者接口,組件負(fù)責(zé)將這些 Service 實(shí)現(xiàn)并注冊(cè)到一個(gè)統(tǒng)一的路由 Router 中去。如果要使用某個(gè)組件的功能,只需要向 Router 請(qǐng)求這個(gè) Service 的實(shí)現(xiàn),具體的實(shí)現(xiàn)細(xì)節(jié)我們?nèi)徊魂P(guān)心,只要能返回我們需要的結(jié)果就可以了。這與 Binder 的 C/S 架構(gòu)很相像。

因?yàn)槲覀兘M件之間的數(shù)據(jù)傳遞都是基于接口編程的,接口和實(shí)現(xiàn)是完全分離的,所以組件之間就可以做到解耦,我們可以對(duì)組件進(jìn)行替換、刪除等動(dòng)態(tài)管理。這里面有幾個(gè)小問(wèn)題需要明確:

組件怎么暴露自己提供的服務(wù)呢?在項(xiàng)目中我們簡(jiǎn)單起見(jiàn),專門(mén)建立了一個(gè) componentservice 的依賴庫(kù),里面定義了每個(gè)組件向外提供的 service 和一些公共 model。將所有組件的 service 整合在一起,是為了在拆分初期操作更為簡(jiǎn)單,后面需要改為自動(dòng)化的方式來(lái)生成。這個(gè)依賴庫(kù)需要嚴(yán)格遵循開(kāi)閉原則,以避免出現(xiàn)版本兼容等問(wèn)題。

service 的具體實(shí)現(xiàn)是由所屬組件注冊(cè)到 Router 中的,那么是在什么時(shí)間注冊(cè)的呢?這個(gè)就涉及到組件的加載等生命周期,我們?cè)诤竺鎸iT(mén)介紹。

一個(gè)很容易犯的小錯(cuò)誤就是通過(guò)持久化的方式來(lái)傳遞數(shù)據(jù),例如 file、sharedpreference 等方式,這個(gè)是需要避免的。

下面就是加上數(shù)據(jù)傳輸功能之后的架構(gòu)圖:

 

 

組件之間的數(shù)據(jù)傳輸

 

 

2.4 組件之間的 UI 跳轉(zhuǎn)

可以說(shuō) UI 的跳轉(zhuǎn)也是組件提供的一種特殊的服務(wù),可以歸屬到上面的數(shù)據(jù)傳遞中去。不過(guò)一般 UI 的跳轉(zhuǎn)我們會(huì)單獨(dú)處理,一般通過(guò)短鏈的方式來(lái)跳轉(zhuǎn)到具體的 Activity。每個(gè)組件可以注冊(cè)自己所能處理的短鏈的 schme 和 host,并定義傳輸數(shù)據(jù)的格式。然后注冊(cè)到統(tǒng)一的 UIRouter 中,UIRouter 通過(guò) schme 和 host 的匹配關(guān)系負(fù)責(zé)分發(fā)路由。

UI 跳轉(zhuǎn)部分的具體實(shí)現(xiàn)是通過(guò)在每個(gè) Activity 上添加注解,然后通過(guò) apt 形成具體的邏輯代碼。這個(gè)也是目前 Android 中 UI 路由的主流實(shí)現(xiàn)方式。

2.5 組件的生命周期

由于我們要?jiǎng)討B(tài)的管理組件,所以給每個(gè)組件添加幾個(gè)生命周期狀態(tài):加載、卸載和降維。為此我們給每個(gè)組件增加一個(gè) ApplicationLike 類,里面定義了 onCreate 和 onStop 兩個(gè)生命周期函數(shù)。

加載:上面講了,每個(gè)組件負(fù)責(zé)將自己的服務(wù)實(shí)現(xiàn)注冊(cè)到 Router 中,其具體的實(shí)現(xiàn)代碼就寫(xiě)在 onCreate 方法中。那么主項(xiàng)目調(diào)用這個(gè) onCreate 方法就稱之為組件的加載,因?yàn)橐坏?onCreate 方法執(zhí)行完,組件就把自己的服務(wù)注冊(cè)到 Router 里面去了,其他組件就可以直接使用這個(gè)服務(wù)了。

卸載:卸載與加載基本一致,所不同的就是調(diào)用 ApplicationLike 的 onStop 方法,在這個(gè)方法中每個(gè)組件將自己的服務(wù)實(shí)現(xiàn)從 Router 中取消注冊(cè)。不過(guò)這種使用場(chǎng)景可能比較少,一般適用于一些只用一次的組件。

降維:降維使用的場(chǎng)景更為少見(jiàn),比如一個(gè)組件出現(xiàn)了問(wèn)題,我們想把這個(gè)組件從本地實(shí)現(xiàn)改為一個(gè) wap 頁(yè)。降維一般需要后臺(tái)配置才生效,可以在 onCreate 對(duì)線上配置進(jìn)行檢查,如果需要降維,則把所有的 UI 跳轉(zhuǎn)到配置的 wap 頁(yè)上面去。

一個(gè)小的細(xì)節(jié)是,主項(xiàng)目負(fù)責(zé)加載組件,由于主項(xiàng)目和組件之間是隔離的,那么主項(xiàng)目如何調(diào)用組件 ApplicationLike 的生命周期方法呢,目前我們采用的是基于編譯期字節(jié)碼插入的方式,掃描所有的 ApplicationLike 類(其有一個(gè)共同的父類),然后通過(guò) javassisit 在主項(xiàng)目的 onCreate 中插入調(diào)用 ApplicationLike.onCreate 的代碼。

我們?cè)賰?yōu)化一下組件化的架構(gòu)圖:

 

 

 

 

組件的生命周期

2.6 集成調(diào)試

每個(gè)組件單獨(dú)調(diào)試通過(guò)并不意味著集成在一起沒(méi)有問(wèn)題,因此在開(kāi)發(fā)后期我們需要把幾個(gè)組件機(jī)集成到一個(gè) app 里面去驗(yàn)證。由于我們上面的機(jī)制保證了組件之間的隔離,所以我們可以任意選擇幾個(gè)組件參與集成。這種按需索取的加載機(jī)制可以保證在集成調(diào)試中有很大的靈活性,并且可以加大的加快編譯速度。

我們的做法是這樣的,每個(gè)組件開(kāi)發(fā)完成之后,發(fā)布一個(gè) relaese 的 aar 到一個(gè)公共倉(cāng)庫(kù),一般是本地的 maven 庫(kù)。然后主項(xiàng)目通過(guò)參數(shù)配置要集成的組件就可以了。所以我們?cè)偕晕⒏膭?dòng)一下組件與主項(xiàng)目之間的連接線,形成的最終組件化架構(gòu)圖如下:

 

 

 

 

最終結(jié)構(gòu)圖

2.7 代碼隔離

此時(shí)在回顧我們?cè)趧傞_(kāi)始拆分組件化是提出的三個(gè)問(wèn)題,應(yīng)該說(shuō)都找到了解決方式,但是還有一個(gè)隱患沒(méi)有解決,那就是我們可以使用 compile project(xxx:reader.aar) 來(lái)引入組件嗎?雖然我們?cè)跀?shù)據(jù)傳輸章節(jié)使用了接口 + 實(shí)現(xiàn)的架構(gòu),組件之間必須針對(duì)接口編程,但是一旦我們引入了 reader.aar,那我們就完全可以直接使用到其中的實(shí)現(xiàn)類啊,這樣我們針對(duì)接口編程的規(guī)范就成了一紙空文。千里之堤毀于蟻穴,只要有代碼(不論是有意還是無(wú)意)是這么做了,我們前面的工作就白費(fèi)了。

我們希望只在 assembleDebug 或者 assembleRelease 的時(shí)候把 aar 引入進(jìn)來(lái),而在開(kāi)發(fā)階段,所有組件都是看不到的,這樣就從根本上杜絕了引用實(shí)現(xiàn)類的問(wèn)題。我們把這個(gè)問(wèn)題交給 gradle 來(lái)解決,我們創(chuàng)建一個(gè) gradle 插件,然后每個(gè)組件都 apply 這個(gè)插件,插件的配置代碼也比較簡(jiǎn)單:

  1. // 根據(jù)配置添加各種組件依賴,并且自動(dòng)化生成組件加載代碼 
  2. if (project.android instanceof AppExtension) { 
  3.        AssembleTask assembleTask = getTaskInfo(project.gradle.startParameter.taskNames) 
  4.        if (assembleTask.isAssemble 
  5.                && (assembleTask.modules.contains("all") || assembleTask.modules.contains(module))) { 
  6.          // 添加組件依賴 
  7.           project.dependencies.add("compile","xxx:reader-release@aar"
  8.          // 字節(jié)碼插入的部分也在這里實(shí)現(xiàn) 
  9.        } 
  10.  
  11. private AssembleTask getTaskInfo(List<String> taskNames) { 
  12.    AssembleTask assembleTask = new AssembleTask(); 
  13.    for (String task : taskNames) { 
  14.        if (task.toUpperCase().contains("ASSEMBLE")) { 
  15.            assembleTask.isAssemble = true
  16.            String[] strs = task.split(":"
  17.            assembleTask.modules.add(strs.length > 1 ? strs[strs.length - 2] : "all"); 
  18.        } 
  19.    } 
  20.    return assembleTask 

 

三、組件化的拆分步驟和動(dòng)態(tài)需求

3.1 拆分原則

組件化的拆分是個(gè)龐大的工程,特別是從幾十萬(wàn)行代碼的大工程拆分出去,所要考慮的事情千頭萬(wàn)緒。為此我覺(jué)得可以分成三步:

從產(chǎn)品需求到開(kāi)發(fā)階段再到運(yùn)營(yíng)階段都有清晰邊界的功能開(kāi)始拆分,比如讀書(shū)模塊、直播模塊等,這些開(kāi)始分批先拆分出去

在拆分中,造成組件依賴主項(xiàng)目的依賴的模塊繼續(xù)拆出去,比如賬戶體系等

最終主項(xiàng)目就是一個(gè) Host,包含很小的功能模塊(比如啟動(dòng)圖)以及組件之間的拼接邏輯

3.2 組件化的動(dòng)態(tài)需求

最開(kāi)始我們講到,理想的代碼組織形式是插件化的方式,屆時(shí)就具備了完備的運(yùn)行時(shí)動(dòng)態(tài)化。在向插件化遷徙的過(guò)程中,我們可以通過(guò)下面的集中方式來(lái)實(shí)現(xiàn)編譯速度的提升和動(dòng)態(tài)更新。

在快速編譯上,采用組件級(jí)別的增量編譯。在抽離組件之前可以使用代碼級(jí)別的增量編譯工具如 freeline(但 databinding 支持較差)、fastdex 等

動(dòng)態(tài)更新方面,暫時(shí)不支持新增組件等大的功能改進(jìn)。可以臨時(shí)采用方法級(jí)別的熱修復(fù)或者功能級(jí)別的 Tinker 等工具,Tinker 的接入成本較高。

四、總結(jié)

本文是筆者在設(shè)計(jì)“得到 app”的組件化中總結(jié)一些想法,在設(shè)計(jì)之初參考了目前已有的組件化和插件化方案,站在巨人的肩膀上又加了一點(diǎn)自己的想法,主要是組件化生命周期以及完全的代碼隔離方面。特別是***的代碼隔離,不僅要有規(guī)范上的約束(針對(duì)接口編程),更要有機(jī)制保證開(kāi)發(fā)者不犯錯(cuò),我覺(jué)得只有做到這一點(diǎn)才能認(rèn)為是一個(gè)徹底的組件化方案。 

責(zé)任編輯:龐桂玉 來(lái)源: 移動(dòng)開(kāi)發(fā)前線
相關(guān)推薦

2017-01-19 18:58:11

iOS組件化方案

2022-01-17 11:41:50

前端Vite組件

2022-08-03 09:58:03

跨端框架實(shí)踐

2021-09-16 18:44:05

京東云PaaS平臺(tái)Android

2019-07-22 10:42:11

React組件前端

2017-05-18 11:43:41

Android模塊化軟件

2020-03-03 14:15:49

Redis持久化數(shù)據(jù)庫(kù)

2017-02-13 18:46:38

Android模塊化組件化

2021-05-13 08:55:33

Android架構(gòu)功能

2020-12-29 08:04:16

可視化地圖組件日歷組件

2019-01-15 14:11:50

Android框架組件化

2019-02-19 10:12:41

Redis分片數(shù)據(jù)

2022-05-26 10:13:22

C/C++GCC插件單元測(cè)試

2018-05-04 14:00:24

2015-12-16 13:34:27

斐訊

2013-05-16 11:07:37

Android開(kāi)發(fā)Android應(yīng)用自動(dòng)化測(cè)試

2018-03-28 09:53:50

Android架構(gòu)演進(jìn)

2017-05-17 15:50:34

開(kāi)發(fā)前端react

2023-11-16 11:34:05

BI大數(shù)據(jù)

2017-02-28 21:57:05

React組件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: www.久久.com | 久久免费小视频 | 精品三级在线观看 | 本道综合精品 | 99久久久久久 | 亚洲精选一区 | 狠狠狠| 久国产视频| 亚洲天堂久久 | 精品久久久久久亚洲精品 | 精品久久亚洲 | 伊人久久免费 | 亚洲精品久久嫩草网站秘色 | 日本在线免费观看 | 蜜桃臀av一区二区三区 | 北条麻妃99精品青青久久 | 91电影| 男女羞羞视频在线观看 | 国产在线一区二 | 亚洲激情综合网 | 欧美一区二区在线免费观看 | 一级片在线观看 | 少妇无套高潮一二三区 | 久久免费小视频 | 国产精品资源在线观看 | 一区二区日本 | 久久蜜桃av一区二区天堂 | 91精品久久久久久久久 | 亚洲天堂二区 | 91福利在线观看视频 | 欧美在线国产精品 | 久久最新 | www免费视频 | 精品久久久网站 | 91久久久久久久 | 粉嫩一区二区三区四区公司1 | 色综合久久久久 | 国产精品久久久久久久久久久免费看 | 久久久久久国产精品免费免费 | 久久久久国产一区二区三区 | 国产清纯白嫩初高生在线播放视频 |