精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

瘦身50%-70%,攜程 Taro 小程序樣式 Size 縮減方案

人工智能 新聞
本文樣式方案學習了 cssModules 解決樣式沖突的基本原理,并在此基礎上改進以達到縮減樣式文件 Size 的目的。

作者簡介

Can,攜程前端開發,目前從事小程序開發工作,對編譯打包技術、小程序跨平臺解決方案有濃厚興趣。

一、概述

目前我們團隊小程序是使用 Taro 跨端方案 React 框架進行開發,基于現有樣式方案,在編譯打包后會產生大量的樣式代碼冗余,在項目編譯后的產物中占有較大比例。

分析了編譯后的樣式代碼后,我們發現冗余代碼主要體現在兩個方面:

  • 項目樣式文件中大量使用了父子選擇器作為作用域進行樣式隔離,編譯后出現類名大量重復冗余。如以下 SCSS 文件樣式代碼中,編譯后 .box .item 重復冗余了三次。
// 編譯前代碼
.box {
  .item {
    .item1 {}
    .item2 {}
    .item3 {}
    .item4 {}
  }
}
// 編譯后代碼
.box .item .item1 {}
.box .item .item2 {}
.box .item .item3 {}
.box .item .item4 {}
  • 樣式代碼中大量屬性值重復冗余。如最常用的 display: flex 屬性值,在項目中可能存在幾百上千份重復冗余,而且為了兼容性開啟了 Autoprefixer 插件后, display:flex 將會變成 display:-webkit-flex;display:-ms-flexbox;display:flex; ,使得樣式文件屬性值的冗余情況更為嚴重。

針對 Taro項目 React 框架小程序遇到的以上問題,本文將介紹一種新的樣式解決方案。本方案在較少改變現有開發體驗的條件下,采用 cssModules 樣式方案語法要求,利用 Taro 插件的便利性給出對應的解決方案,以此對產物進行“瘦身”。最終樣式文件的瘦身效果可以達到 50% - 70%,進一步緩解官方包 Size 的限制,便于業務的高速發展。

二、cssModules 簡單介紹

本文樣式方案學習了 cssModules 解決樣式沖突的基本原理,并在此基礎上改進以達到縮減樣式文件 Size 的目的。因此在正式了解本方案之前,本文先用 Taro 官網中使用 cssModules 方案的例子代碼作為示例,簡單了解下其語法要求與原理。

2.1 語法要求

在配置開啟了 cssModules 后,按照語法要求,Taro 項目中有 index.module.scss 和 index.js 兩個文件,文件代碼如下。cssModules 默認是開啟部分自定義模式轉換,只有文件名中包含 .module. 的樣式文件才會經過 cssModules 轉換處理。在如下 index.module.scss 樣式文件中,我們正常使用了父子選擇器、類選擇器。但是在index.js 文件中,className 賦值不再是字符串,而是 SCSS 文件導出的 Object 的某個 Key,該 Key 為 SCSS 文件中的類選擇器的命名。

import React, { Component } from 'react'
import { View, Text } from '@tarojs/components'
import styles from './index.module.scss'


export default class Index extends Component {
  render() {
    return (
      <View className={styles.test}>
        <Text className={styles.txt}>Hello world!</Text>
      </View>
    )
  }
}
.test {
  color: red;
  .txt {
    font-size: 36px;
  }
}

2.2 原理

Taro 項目開啟 cssModules 配置后,在編譯打包時,會使用實現了 cssModules 規范的 css-loader 對 SCSS 等樣式文件進行處理。它首先會處理原 SCSS 文件中的類選擇器,將類名進行哈希處理得到新類名如 index-module__test___Bm2J6 ,生成新的樣式代碼輸出到最終的 index.wxss,同時保存了原類名與哈希處理后的新類名的映射關系。此后它會將原 SCSS 文件 index.module.scss 編譯為導出了原類名與哈希后的新類名的映射對象。JS 文件在運行時能通過該映射對象獲取到哈希后的新類名,保證該文件類名不會與其他樣式文件的同類名沖突,從而解決樣式沖突問題。以下為編譯后的代碼示例, styles.test 在運行時會會變成 index-module__test___Bm2J6 。

// index.module.scss
export default ({"test":"index-module__test___Bm2J6","txt":"index-module__txt___nIysk"});
// index.wxss
.index-module__test___Bm2J6 {
  color: red;
}
.index-module__test___Bm2J6 .index-module__txt___nIysk {
  font-size: 36rpx;
}

三、方案原理介紹

3.1 基本原理

3.1.1 當前樣式文件 size 分析

在正式介紹本文方案是如何縮減樣式文件 Size 之前,本文通過以下兩個正則去分別匹配打包產物中所有樣式文件的兩個核心組成部分 ClassName 與 PropertyValue,并進行 Size 統計分析。

注:在本文中,有如該 .txt .tit {color: #red;} CssRule代碼,ClassName 指的是其中的 txt 和 tit ,PropertyValue 指的是 color:#red; 。

const classNamePattern = /(?<=\.)[A-Za-z0-9\-_]+(?=\s|{|:)/g // 匹配 ClassName 如 .txt {color: #red;}中的txt
const cssPropertyPattern = /(?<=\{)[^}]+(?=})/g // 匹配PropertyValue, 如 .txt {color: #red;}中  中括號之間的所有內容 color: #red;

下圖是對整個編譯打包后的小程序項目的樣式文件進行組成 Size 分析。通過該圖我們可以發現,我們項目打包編譯后的所有的樣式文件中,ClassName 占用大約有五分之一的空間,而 PropertyValue 則占用了有十分之七的空間,其余空間占比可能是如空格、偽類這種形態存在,本文暫不考慮。

圖片

3.1.2 處理方案

通過上一小節,我們可以知道一個樣式文件中核心主要有兩部分內容,一是 ClassName,二是 PropertyValue。本文樣式方案對這兩部分分別進行了處理來達到節省 Size 的目標。

1)縮減 ClassName 長度

核心就是將原 ClassName 替換成更短且唯一的 ClassName,在解決樣式沖突的同時,也通過縮減了 ClassName 長度節省了 Size。當我們使用 cssModules 時,通常如第二章介紹 cssModules 時的示例代碼一樣,都是將 ClassName 進行 hash 化處理來保證唯一性,但是經過 hash 處理后的 ClassName 長度反而變得更長了,不符合我們縮減樣式代碼 Size 的目標。

本方案是從最短字符開始,逐漸遞增的方式生成全項目唯一的 ClassName,從而保證唯一性的同時能夠保證 ClassName 長度盡可能的短。如第一個解析到的 ClassName 替換成 -a ,第二個解析到的ClassName替換成 -b ,第五十二個解析到的 ClassName 替換成 -Z ,第五十三個解析到的 ClassName 替換成 -aa 。其中 ClassName 前面的 - ,用于防止新生成的類名與未轉換的類名沖突。此外,新生成的 ClassName 注意需要符合規則,本插件算法先取 prevString 中一個字符,后續所有字符可以取任意 charString 中字符。

const prevString = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' // 52個字符數
const charString = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_' // 64個字符數

可能有人擔心,隨著整個項目中 ClassName 申明的越來越多,逐漸遞增生成的 ClassName 也會越來越長,反而導致總 ClassName 過長。通過上述算法,算上最前面加上的  -  , 當使用完三個字符長度的類名可 以替換 52 * 64 = 3328 個 ClassName 了,達到使用完四個字符長度需要 52 * 64 * 64 =  212992 個 className。新生成的 ClassName 不超過四個字符,就可以滿足大部分項目的使用,使用本樣式方案前可以檢索下自己項目中 ClassName 的量級。

2)縮減 PropertyValue

通過上面的分析可以發現,其實占據樣式文件 Size 最多的部分是 PropertyValue,因此縮減 PropertyValue 是本樣式方案能夠節省大量 Size 的核心手段。其實我們在開發時用到的樣式屬性值很多都是重復的,比如開發過程中用到的最多布局屬性 display:flex 。每次用到該屬性都需要新寫一份,而且為了兼容性開啟了Autoprefixer插件, display:flex 將會變成 display:-webkit-flex;display:-ms-flexbox;display:flex; ,這使得樣式文件的 Size 變得更大。本插件是通過盡可能復用 PropertyValue 的方式來縮減 PropertyValue。

本插件會將樣式文件中的僅使用了類選擇器的 CssRule 進行 PropertyValue 拆分,每一次拆分都會生成新的 PropertyValue ClassName。如以下示例代碼,僅類選擇器CssRule txt 被拆分了 _a 和 _b 兩個 PropertyValue ClassName。后續若其他使用僅類選擇器 CssRule 進行拆分時,若有相同的 PropertyValue 就會直接復用 _a 或者 _b 。

// 原代碼
.txt { display: flex;flex: 1; }
// 處理后的代碼
._a {display: -webkit-flex; display: -ms-flexbox;display: flex;}
._b {-webkit-flex: 1;-ms-flex: 1;flex: 1;}

而在使用 cssModules 樣式寫法的 js 文件中也需要進行相應的映射處理,通過 babel 插件在編譯時進行轉換處理,判斷 css 文件的引用關系并進行替換,示例代碼如下。

// 原代碼
import styles from './index.module.scss'
Index = () => {
  return <View className={styles.txt} />
}
// 處理后的代碼
import './index.module.scss'
Index = () => {
  return <View className="_a _b" />
}

本樣式方案通過對僅使用了類選擇器的 CssRule 的 PropertyValue 拆分成新的 PropertyValue ClassName,后續任何進行拆分的地方就可以直接復用該 PropertyValue ClassName,從而可以大量縮減 PropertyValue 重復冗余占用的 Size。

3)插件處理流程

以上兩小節已經介紹了兩個核心縮減 Size 的方案,本小節舉一個更加全面的例子來介紹本插件是如何在編譯時運用以上兩個方案,對樣式文件和 JS 文件進行處理轉化的。主要有以下兩步。

第一步,針對僅使用類選擇器的 CssRule,進行 PropertyValue 拆分。如下示例代碼中, .box{display:flex} 拆分出了 ._a {display: -webkit-flex;display: -ms-flexbox;display: flex;} ,后續 .item1` `.item2 拆分時,直接復用了 ._a ,縮減了 PropertyValue 重復冗余。

第二步,針對非僅使用類選擇器的 CssRule,直接替換成全局唯一且更短的 ClassName。如下示例代碼中, .box .item2{color: red;} ,原選擇器中的 ClassName 直接替換成了更短的 .-a .-b{ color: red;} ,并且添加了該映射關系 styles = {box: "_a -a", item1: "_a _b _c", item2: "_a _b _d -b"} ,并在編譯時進行替換。

// 原代碼
import React from 'react'
import styles from './index.module.scss'


export default Index = () => {


  return <View className={styles.box}>
    <View className={styles.item1}>item1</View>
    <View className={styles.item2}>item2</View>
  </View>
}
// 處理后的代碼
import React from 'react'
import './index.module.scss'
// styles = {box: "_a -a", item1: "_a _b _c", item2: "_a _b _d -b"}
export default Index = () => {


  return <View className="_a -a">
    <View className="_a _b _c">item1</View>
    <View className="_a _b _d -b">item2</View>
  </View>
}
// 原index.module.scss代碼
.box {
    display: flex;
}
.item1{
    display: flex;
    font-size: 32px;
    color: red;
}
.item2{
    display: flex;
    font-size: 32px;
    color: grey;
}
.box .item2{
    color: red;
}
// 處理后index.module.scss代碼
._a {display: -webkit-flex;display: -ms-flexbox;display: flex;}
._b {font-size: 32px;}
._c {color: red;}
._d {color: grey;}
.-a .-b{
    color: red;
}

3.2 需要注意的問題

3.2.1 styles 對象的屬性不支持運行時

cssModules 方案中,JS 文件中引入的樣式文件對象支持運行時計算屬性的,如以下示例寫法。這是因為在打包后的 JS 文件中,保存有一份原 ClassName 與 hash 后新 ClassName 映射關系的對象數據,因此運行時 styles 還能映射屬性,但是這種處理方式會導致 js 文件 size 增大。

import styles from './index.module.scss'
const Index = () => {
  return <View className={styles['t' + 'xt']} />
}

本方案為了盡可能保證項目 Size 足夠小,并沒有采用 cssModules 這種處理方式。本方案在編譯時會直接對原 CLassName 與拆分 PropertyValue 后的新 ClassName 直接進行了替換,如直接把 className={styles.txt} 替換成 className="_a _b" 。

因此本方案 styles 對象不支持如上示例代碼中,運行時計算得到 txt 屬性,如需動態調整樣式有兩種方案,一是直接使用內聯樣式。二是新寫 ClassName 而不是拼接,如className={value ? styles.txt1 : styles.txt2}} 。

3.2.2 僅類選擇器不依賴先后順序定優先級

在上文中,提到過會拆分僅使用類選擇器 CssRule,來盡可能復用已有的 PropertyValue ClassName。但是這種復用是有缺陷的,它會導致 ClassName 的先后順序可能不符合預期,如下代碼所示,通常來說我們認為標題顏色應當是 grey 。

// 原代碼
import styles from './index.module.scss'
const Index = () => {
  return <View className={styles.tit1 + ' ' + styles.tit2}>標題</View>
}
// 處理后的代碼
import styles from './index.module.scss'
const Index = () => {
  return <View className={'_a' + ' ' + '_b'}>標題</View>
}
// 原代碼
.other { color: green; color:red; }
.tit1 { color: red; }
.tit2 { color: green; }
// 處理后的代碼
._a {color:green;}
._b {color:red;}

但是經過本插件復用了 PropertyValue 后,導致 ._b{color:red;} 出現在了 ._a{color:green;} 后面了,此時標題的顏色也就變成了 red ,從而可能不符合開發者預期。

因此需要注意在編寫僅類選擇器 CssRule 的 ClassName 時,不能依賴類選擇器先后順序來定優先級,可通過兄弟選擇器來將優先級提的更高,從而不受先后順序影響,如下代碼示例。這樣就能確定標題顏色一定是 green 。

// 兄弟選擇器來提高優先級
.other { color: green; color:red; }
.tit1 { color: red; }
.tit1.tit2 { color: green; }

四、使用指南

4.1 使用

4.1.1 安裝插件

本樣式方案被集成在該 Taro 插件 taro-plugin-split-class 中,安裝本插件。源碼見倉庫 taro-plugin-split-class

npm install -D taro-plugin-split-class

4.1.2 關閉cssModules功能

在 Taro 配置文件中,使得 mini.posetcss.cssModules.enable = false ,確保 cssModules 功能關閉,如下代碼所示。

// config/index.js
{
    mini: {
        postcss: {
            cssModules: {
                enable: false
           }
        }
    }
}

4.1.3 配置本插件

在 Taro 配置文件中, plugins 配置中加入本插件 taro-plugin-split-class 。本插件支持配置類名轉換白名單(實現功能類似 : global,見 2.4)classNameWhite,比如常用的 iconfont 是不需要轉換的。

plugins: [
    ['taro-plugin-split-class', {
      classNameWhite: ["iconfont", /^ifont-/]
    }]
]

4.2 語法要求

a. 樣式文件命名需以 .module.xxx 結尾,如 index.module.scss,該樣式文件方可被本插件轉化處理。

b. 在 JS 文件中,將樣式文件作為一個對象引入,并將類名作為對象的鍵進行使用。如下代碼所示,使用 className={styles.box} 而不是 className="box" ,其中 box 為定義在樣式文件的中類名。

// 如下
import styles from './index.module.scss'
<View className={styles.box}></View>
// 而不是
import './index.module.scss'
<View className="box"></View>

c. 本方案支持所有選擇器包括父子選擇器、偽類選擇器、兄弟選擇器等等。但請盡可能的使用僅類選擇器來定位元素,這樣做可以便于插件盡可能復用 PropertyValue 從而更好的縮減 Size。本方案解決了類名沖突問題,因此開發者不需要擔心因類名命名簡單而導致的類名沖突。

// 如下僅類選擇器的CssRule
.box {
    display: flex;
    flex-direction: column;
    align-items: center;
}
.tit {
    display: flex;
    font-size: 40px;
    color: red;
}
// 而不是父子選擇器
.box {
    display: flex;
    flex-direction: column;
    align-items: center;
    .tit {
        display: flex;
        font-size: 40px;
        color: red;
    }
}

d. 特殊類名不變

有時候我們希望一些特殊的 ClassName 不變,在 JS 文件中,不從 styles 取類名即可,如下代碼中的 extra 。

import styles from './index.module.scss'
<View className={styles.tit + ' extra'}>標題</View>

但是在樣式文件中默認所有 ClassName 都會被拆分或者壓縮。如下代碼示例, extra 被處理成 -a 。

// 原類名
.extra.tit {
color: blue;
}
// 新類名
.-a.-b {
    color: blue;
}

因此需要特殊標識符讓插件感知到不需要處理該 ClasName。本方案提供了類似 cssModules 的 :global 的解決方案,有兩種使用方式,一是 :global(.extra) ,被包裹的類名不會被替換。

// 編譯前
:global(.extra).tit {
  color: blue;
}
// 編譯后
.extra.-a {
    color: blue;
}

二是以 :global 開頭,后續所有的類名都不會被替換。

// 編譯前
:global .extra1 .extra2 { color: red;}
// 編譯后
.extra1 .extra2 { color: red;}

4.3 打包效果展示

4.3.1 開發環境

使用本插件后,原類名會被替換或拆分成更短且更多的新類名。這樣處理后的新類名可讀性很差,開發者不能很好的定位到原類名代碼。因此在開發環境下,會在更短且更多的新類名前會加上[文件夾_文件名_原類名]。保留了原類名相關信息,便于開發者查找原類名。如下圖代碼所示,原類名為 box ,經過插件拆分和縮短后的新類名為 _a _g _h -c ,在新類名前加上了 index_indes-module_box ,最終展示的完整類名為 index_index-module_box _a _g _h -c 。

4.3.2 生產環境

在生產環境了,不需要考慮新類名可讀性,因此直接會直接將類名完全替換為新類名。如下圖代碼所示, box 直接被替換成 _a _g _h -c 。

圖片

五、方案分析

5.1 實踐效果

5.1.1 頁面改造前后對比

在使用本樣式方案對某個頁面進行改造后,改造前后 Size 對比如下。可以發現樣式文件縮減了 44KB,縮減了將近 70% 的 Size,JS 文件有這 2kb 的增長。


JS文件

 樣式文件 

總和

 使用前

54kb

63kb

117kb

 使用后

56kb

19kb

75kb

使用前編譯后文件 Size 如下圖:

圖片


使用后編譯后文件 Size 如下圖:

圖片


5.1.2 重構頁面橫向對比

最近我們項目重構了兩個大型訂單詳情頁面,本小節以這兩個頁面重構后的代碼為例,分析編譯打包前后的 Size 并進行橫向對比。

整理出如下表格:


樣式編碼字符數

打包后實際Size

未使用本樣式方案的訂單詳情頁1

3620

86kb

使用本樣式方案的訂單詳情頁2

6615

73kb

兩訂單詳情頁代碼組織結構類似,因此將它們進行橫向對比。未采用本樣式方案的訂單詳情頁 1 的樣式編碼字符數為 3620,打包后實際 Size 為 86kb。若訂單詳情頁 2 未使用本樣式方案,打包前樣式編碼字符數為 6615,則預期打包后實際 Size 為 6615 / 3620 \* 86kb = 157kb,但訂單詳情頁使用了本樣式方案實際打包后為 73kb,相對于 157kb,縮減了 50% 左右的 Size。

以下為未使用本樣式方案的訂單詳情頁 1,該目錄下樣式文件包括了 50 個樣式文件,共計 3620 個字符,最終打包出來的樣式文件的 Size 為 86kb。

圖片


圖片

以下為使用了本樣式方案的訂單詳情頁 2,該目錄下樣式文件包括了 96 個樣式文件,共計 6615 個字符,最終打包出來的樣式文件 Size 為 73kb。

圖片


5.2 Size 縮減效果分析

以上兩個實踐效果,相較于項目中原樣式寫法方案,使用本方案后,主要從以下三個方面節省了 Size。

a. 本方案解決了樣式沖突問題,編寫樣式代碼時可以不再用父子選擇器的方式來進行樣式作用域隔離,減少了祖先選擇器的冗余。如下使用了 sass 預處理器的樣式代碼所示,我們可以發現在最終編譯生成的代碼中, .box .item 冗余了三次,而且若繼續在 .box .item 下每新增一個葉子節點 .item* , .box .item 都會冗余一次。因此項目中使用父子選擇器這種方式來隔離作用域,會導致大量的祖先選擇器冗余。

// 編譯前代碼
.box {
  .item {
  .item1 {}
  .item2 {}
  .item3 {}
  .item4 {}
  }
}
// 編譯后代碼
.box .item .item1 {}
.box .item .item2 {}
.box .item .item3 {}
.box .item .item4 {}

b. 將原 ClassName 直接縮短成更短的 ClassName,直接減少了字符數。這種方式較為直接,但優化效果有限。

c. 本方案盡可能拆分樣式文件中僅類選擇器的 CssRule,生成并復用 PropertyValue ClassName,盡可能減少了 PropertyValue 的重復冗余。雖然在 JS 文件中 ClassName 被替換成更短但更多的 PropertyValue ClassName,有一定的 Size 增加,如在實踐效果 1 中,實踐后 JS 文件有 2KB 的增長。但是相比于樣式文件 Size 上的縮減效果可以忽略不計。

5.3 Size 增長分析

隨著樣式文件越多,采用本樣式方案的項目,樣式文件 Size 增長幅度將增長會越緩慢。本方案要求以僅類選擇器的方式為主,少量場景使用其他選擇器為輔的方式進行編寫樣式代碼。隨著項目中樣式代碼越來越多,僅類選擇器 CssRule 經過本插件處理拆分生成的可復用的 PropertyValue CssRule 會越來越多。此時,在按要求新寫僅類選擇器 CssRule 使用到某個 PropertyValue 時,可復用的概率會更高。高概率的每一次復用都會節省一部分 Size,使得最終編譯打包后生成的樣式文件 Size 增長曲率逐漸放緩。

六、總結

針對 Taro 項目 React 框架小程序,本文介紹了一種新的樣式解決方案,該方案被集成為一個 Taro 插件的形式,可以在在較少改變現有開發體驗的條件下,緩解樣式代碼的冗余問題。

本樣式方案學習借鑒了 cssModules 樣式方案的語法規則以及原理,解決了樣式沖突的問題,并且在此基礎上從縮減 ClassName 長度和縮減 PropertyValue 兩個方面實現了 Size 上的縮減,最終樣式文件的瘦身效果可以達到 50%-70%。這有利緩解官方包 Size 的限制,便于業務的高速發展。

七、vscode 插件推薦

本方案基本語法跟 cssModules 一致,因此可以直接借助現有的 cssModules 插件,提升開發體驗。

7.1 CSS-Modules-transform 插件

該插件支持讓項目現有 JS 代碼快速轉成 cssModules 語法,將原類名使用方式,一鍵替換成本方案要求的類名使用語法,如 classname="a1" => className={styles.a1} 。需要注意的是,一鍵替換只支持非運行時的語法,運行時的語法還是需要手動替換。可以高效提高現有樣式方案轉化效率。

7.2 CSS Modules 插件

CSS Modules 插件支持自動補全和類型定義,提高開發體驗。

八、文章參考

  • GitHub - css-modules/css-modules: Documentation about css-modules
  • cssModules插件 
責任編輯:張燕妮 來源: 攜程技術
相關推薦

2022-08-12 08:38:08

攜程小程序Taro跨端解決方案

2022-06-10 08:43:20

攜程小程序Size治理Size檢查

2023-08-18 10:49:14

開發攜程

2023-04-14 10:29:24

小程序實踐

2024-01-12 09:31:08

Java代碼

2023-03-19 11:47:57

Taro小程序持續集

2020-11-13 15:20:16

SCSS代碼前端

2009-03-05 09:27:31

2014-12-25 17:51:07

2023-04-24 15:10:23

優化方案

2024-01-22 16:24:10

框架小程序開發

2022-07-15 12:58:02

鴻蒙攜程華為

2022-05-13 09:27:55

Widget機票業務App

2024-09-10 10:42:27

2017-04-11 15:11:52

ABtestABT變量法

2022-10-21 10:40:08

攜程酒店MySQL慢查詢

2022-08-12 08:34:32

攜程數據庫上云

2015-05-29 13:59:53

2023-02-08 16:34:05

數據庫工具

2022-07-08 09:38:27

攜程酒店Flutter技術跨平臺整合
點贊
收藏

51CTO技術棧公眾號

牛牛精品一区二区| 水莓100在线视频| 91精品观看| 欧美变态口味重另类| 热99这里只有精品| 国产视频网站在线| 国产呦精品一区二区三区网站| www.久久色.com| 国产精品久久精品视| 国产一级18片视频| 久久大综合网| 亚洲国产小视频在线观看| 日韩免费高清在线| 好看的中文字幕在线播放| 国产日韩欧美在线一区| 91久久极品少妇xxxxⅹ软件| 亚州成人在线电影| 亚洲iv一区二区三区| 国产专区第一页| 91超碰成人| 亚洲免费电影一区| 波多野结衣三级视频| 天天综合网天天| 亚洲国产裸拍裸体视频在线观看乱了| 视频一区不卡| 亚州视频一区二区三区| 蜜桃免费网站一区二区三区| 欧美一区二区三区…… | 国产精品66| 亚洲成人av福利| 国产成人三级视频| 91高清在线视频| 99久久精品国产一区二区三区 | 亚洲精品a区| 欧美日韩中字一区| 日日碰狠狠躁久久躁婷婷| 超碰在线资源| 亚洲一区二区三区美女| 国产欧美综合一区| 欧美激情办公室videoshd| 久久午夜免费电影| 久久香蕉综合色| 色婷婷中文字幕| av不卡免费电影| 国产免费一区二区| 亚洲精品无码久久久| 国产成人自拍在线| 99精品国产一区二区| 国产欧美熟妇另类久久久| 另类欧美日韩国产在线| 国产美女精品免费电影| 久久影视中文字幕| 奇米精品一区二区三区在线观看一| 97av在线播放| 日本a在线观看| 亚洲电影av| 91高清视频在线免费观看| 日韩成人一区二区三区| 国产亚洲亚洲| 日本久久久久久| 亚洲高清视频免费观看| 日韩va亚洲va欧美va久久| 国产精品久久久久久av下载红粉| 成人毛片一区二区三区| 久久精品久久精品| 成人日韩在线电影| 丁香花免费高清完整在线播放 | 亚洲欧美va天堂人熟伦| 免费黄色成人| 宅男66日本亚洲欧美视频| 波多野结衣欲乱| 亚洲理论电影网| 欧美人交a欧美精品| 国产亚洲精品久久久久久无几年桃 | 免费无码毛片一区二区app| 欧美天堂亚洲电影院在线观看| 欧美国产亚洲视频| 成年人免费高清视频| 日韩激情一区二区| 国产日韩一区在线| www日本视频| 99久久99久久精品免费看蜜桃| 久久久久久99| 91sp网站在线观看入口| 亚洲美女在线一区| 日本福利视频在线| 粉嫩91精品久久久久久久99蜜桃| 欧美一区二区久久| 97人妻精品一区二区三区免费 | 丰满女人性猛交| 国产激情在线观看| 日韩精品1区2区3区| 国产xxx69麻豆国语对白| 中文字幕 亚洲视频| 国产精品中文字幕日韩精品| 久久综合一区| 黄av在线播放| 欧美日韩免费看| 亚洲va在线va天堂va偷拍| 国产日韩三级| 久久精品99久久久香蕉| av黄色在线看| 国产精品一区一区三区| 欧美日韩一区二区视频在线观看 | 人妻va精品va欧美va| 国产三级久久久| 国产精品久久..4399| 欧美另类激情| 国产网站欧美日韩免费精品在线观看| 三级在线观看免费大全| 视频一区视频二区中文字幕| 91久久大香伊蕉在人线| 最新av网站在线观看| 精品久久久久久久中文字幕| 日韩av影视大全| 国产一区二区三区91| 久久久最新网址| 国产喷水吹潮视频www| 亚洲国产精品t66y| 国产主播在线看| 久久99国产精品久久99大师| 久久中文字幕视频| 一区二区视频网站| 久久精品免视看| 激情综合在线观看| 高潮久久久久久久久久久久久久| 在线观看日韩av| 久久久久99精品成人片我成大片| 成人晚上爱看视频| 超碰97在线看| 亚洲精品在线a| 久久中文字幕视频| 99久久久国产精品无码免费| 国产亚洲欧美日韩俺去了| 国产在线青青草| 国产精品一线| 午夜精品久久久久久久99热| 亚洲第一精品网站| 亚洲主播在线观看| 久久久精品人妻一区二区三区| 亚洲男女av一区二区| 国产欧美va欧美va香蕉在线| freemovies性欧美| 欧美亚洲精品一区| avhd101老司机| 国产一级视频在线| 国产欧美日韩在线一区二区| 8x海外华人永久免费日韩内陆视频| 亚洲国产成人一区二区| 亚洲精品福利视频网站| 国产资源中文字幕| 欧美激情1区2区3区| 99国产超薄丝袜足j在线观看 | 隔壁老王国产在线精品| 99久久精品国产一区色| 亚洲女厕所小便bbb| 国产又粗又猛又爽又黄| 国内精品久久久久久久影视麻豆| 亚洲综合精品伊人久久| 久久综合网导航| 欧美伊人久久久久久久久影院| b站大片免费直播| 免费看欧美美女黄的网站| 一区二区精品视频| 国产精品久久久久久av公交车| 欧美成人精品在线观看| 日本美女一级视频| 色综合天天综合给合国产| 成人性生交大免费看| 青娱乐精品在线视频| 一区二区三区四区视频在线| 日本99精品| 久久成年人视频| 人人妻人人澡人人爽久久av| 欧美性猛交xxxx偷拍洗澡| 男人的天堂av网| 国产精品一区二区三区99| 一二三四视频社区在线| 精品视频97| 91精品入口蜜桃| 蜜桃视频在线网站| 日韩一区二区久久久| 亚洲精品一区二区三区蜜桃 | 91资源在线视频| 亚洲香肠在线观看| 久久精品无码一区| 国产毛片精品一区| 久草精品在线播放| 欧美影院一区| 欧美一级片免费观看| 国产成人久久精品一区二区三区| 国产69精品久久久久99| seseavlu视频在线| 亚洲第一色中文字幕| 中文字幕在线播放日韩| 亚洲第一激情av| 永久免费未视频| 91丝袜呻吟高潮美腿白嫩在线观看| 黄色一级片免费的| 欧美一级二区| 日韩精品综合在线| 久久国产精品亚洲人一区二区三区| 成人av蜜桃| 日本一区二区三区中文字幕 | 电影一区二区| 97视频在线播放| 国产高清一区二区三区视频 | 日本不卡一区二区| 男人插女人视频在线观看| 午夜片欧美伦| 日韩资源av在线| 日韩av三区| 波多野结衣一区二区三区在线观看| 不卡亚洲精品| 日本伊人精品一区二区三区介绍| 欧美性猛片xxxxx免费中国| 最近2019年好看中文字幕视频 | 亚洲六月丁香色婷婷综合久久| 人妻丰满熟妇av无码久久洗澡 | 久久婷婷一区| 国产二级片在线观看| 欧美日韩爆操| 9l视频自拍9l视频自拍| 国产亚洲一区| 欧美aaaaa喷水| 欧美精品中文字幕亚洲专区| 成人毛片网站| 日本成人精品| 亚洲一区二区三区久久| 四虎地址8848精品| 国产精品网站入口| 成人日韩在线| 国产99久久精品一区二区永久免费| 麻豆mv在线看| 26uuu另类亚洲欧美日本老年| 黑人玩欧美人三根一起进| 九九热精品视频在线播放| 成人免费看片| 欧美xxxx综合视频| 午夜在线激情影院| 欧美激情一区二区三级高清视频| www在线免费观看视频| 久久中文精品视频| 蜜臀av在线播放| 欧美放荡办公室videos4k| 在线观看中文字幕的网站| 久久国产色av| 欧美性爽视频| 91精品国产色综合久久不卡98口 | 国产又黄又粗又猛又爽的视频| 国产999精品久久| 中文字幕在线视频播放| 99久久99久久精品免费观看 | 日韩av.com| 国产乱对白刺激视频不卡| 日批视频在线看| 成人一区二区三区在线观看 | 国产精品乱码一区二三区小蝌蚪| 国产一区二区三区四区在线| 国产精品久久久久久久久久久免费看 | 国产伦精品一区二区三区在线播放| 国产精品区二区三区日本| 开心激情综合| 欧美在线3区| 91视频久久| 免费视频爱爱太爽了| 午夜一级久久| 午夜免费一级片| 成人视屏免费看| 37p粉嫩大胆色噜噜噜| 欧美韩日一区二区三区四区| 少妇高潮在线观看| 亚洲网友自拍偷拍| 最近免费中文字幕大全免费版视频| 欧美日韩一区二区电影| av中文字幕免费在线观看| 亚洲高清在线观看| 国产视频第一页在线观看| 日韩视频免费观看| 高清电影在线观看免费| 国产99视频在线观看| 四虎影视国产精品| 精品国产一区二区三区麻豆小说| 国产九一精品| 少妇一晚三次一区二区三区| 老司机久久99久久精品播放免费 | av不卡一区二区三区| 日本美女xxx| 亚洲成人动漫在线观看| 狠狠躁夜夜躁人人爽视频| 日韩美女主播在线视频一区二区三区 | 99久re热视频精品98| 性一交一乱一区二区洋洋av| 国产精品嫩草影视| 久久九九全国免费| avtt天堂在线| 欧美性猛交xxxx乱大交退制版| 亚洲精品无码专区| www.亚洲人.com| 一级毛片久久久| 99三级在线| 日韩一级毛片| 日韩精品一区二区三区色欲av| 国产xxx精品视频大全| 人成免费在线视频| 黑人巨大精品欧美一区免费视频| 国产免费无遮挡| 亚洲欧洲中文天堂| 爱啪啪综合导航| 91精品国产91久久久久青草| 第一会所sis001亚洲| 欧美精品一区二区三区三州| 美女国产一区二区三区| 波多野结衣 在线| 亚洲五码中文字幕| a在线观看视频| 精品激情国产视频| 黄色成人小视频| 日本亚洲导航| 久久成人亚洲| 超碰97在线资源站| 亚洲成人免费视频| a天堂在线观看视频| 久久精品精品电影网| 国内自拍亚洲| 亚洲一区二区三区加勒比| 日产国产欧美视频一区精品| 自拍偷拍中文字幕| 婷婷久久综合九色综合伊人色| 亚洲av永久无码国产精品久久| 超薄丝袜一区二区| 国产高清日韩| 麻豆中文字幕在线观看| 久久精品国产99久久6| 亚洲国产中文字幕在线视频综合| 免费一级黄色大片| 制服丝袜激情欧洲亚洲| 午夜不卡视频| 国产日韩欧美在线看| 国产精品国内免费一区二区三区| 99视频在线视频| 亚洲国产高清aⅴ视频| 亚洲精品国产精品乱码视色| 国产亚洲精品久久久久久777| 欧美片第一页| 欧美重口乱码一区二区| 久久资源在线| wwwww黄色| 3d动漫精品啪啪1区2区免费| 免费看美女视频在线网站| 91九色单男在线观看| 中出一区二区| 久久久久国产免费| 香蕉加勒比综合久久| 天堂成人在线观看| 欧美一性一乱一交一视频| 欧美人与牛zoz0性行为| 日韩av片网站| 亚洲视频中文字幕| 丰满熟妇人妻中文字幕| 久久久久久久国产| 香蕉人人精品| 亚洲第一中文av| 亚洲精品国产视频| 日本精品一二区| 国产精品高潮呻吟视频| 色乱码一区二区三区网站| av在线免费看片| 午夜视频一区在线观看| 国产免费a∨片在线观看不卡| 国产精品一区二区久久国产| 亚洲综合色站| 成人欧美精品一区二区| 色妹子一区二区| 成人毛片av在线| 麻豆91蜜桃| 韩国毛片一区二区三区| 日本a在线观看| 色一情一乱一区二区| 9l亚洲国产成人精品一区二三| 两根大肉大捧一进一出好爽视频| 中文字幕精品三区| www久久久com| 国产精品久久久久免费a∨大胸| 91精品国产成人观看| 粉嫩av懂色av蜜臀av分享| 欧美日韩一级黄| 91破解版在线观看| 亚洲精品在线免费| 成人午夜在线视频| 中文字幕+乱码+中文乱码91| 久久久免费观看视频| 日本女优一区| 日韩免费高清一区二区| 欧美日本在线视频| 成人香蕉视频| 精品人妻人人做人人爽| 国产日韩欧美精品电影三级在线| 亚洲a视频在线| 国产精品视频网|