精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

国产suv精品一区二区6| 日韩一区二区三区精品| 国产超碰在线一区| 久久久免费观看视频| 中文字幕99页| 周于希免费高清在线观看| 久久色在线观看| 午夜欧美大片免费观看| 免费看黄色的视频| 电影中文字幕一区二区| 亚洲成av人片在www色猫咪| 国内成+人亚洲| 波多野结衣影片| 亚洲色图美女| 欧美精品在线视频| 久无码久无码av无码| 六十路在线观看| 精品伊人久久久久7777人| 色综合五月天导航| 国产精品三级在线观看无码| 国产在视频一区二区三区吞精| 亚洲三级在线免费| 欧美精品成人一区二区在线观看 | 日日躁夜夜躁aaaabbbb| 在线中文字幕电影| 久久蜜桃av一区二区天堂 | 国产一区二区在线视频播放| 91精品专区| 99精品视频一区二区三区| 国产美女久久久| 欧美成人精品欧美一级乱黄| 成人羞羞视频播放网站| 日韩女优毛片在线| 亚洲福利精品视频| av成人 com a| 一区二区三区日韩欧美| 日韩三级电影免费观看| 亚洲精品一区二区三区不卡| 免费看精品久久片| 97国产精品视频人人做人人爱| 一本在线免费视频| 免费成人网www| 精品国产一区二区国模嫣然| 日本中文字幕精品—区二区| 成人小电影网站| 亚洲综合av网| 超碰成人在线免费观看| 极品美乳网红视频免费在线观看 | 黄色电影免费在线看| 国产成人久久精品77777最新版本 国产成人鲁色资源国产91色综 | 日本一区二区在线播放| 久久亚洲AV无码| 影音先锋成人在线电影| 中文字幕视频一区二区在线有码| 五月天丁香社区| 久久9999免费视频| 欧美群妇大交群的观看方式| 成熟老妇女视频| 男人天堂视频在线观看| 亚洲精品高清在线观看| 中文字幕第一页亚洲| 8888四色奇米在线观看| 国产女主播视频一区二区| 欧美日韩在线观看一区二区三区 | 国产精品一二三四五| 国产欧美亚洲精品| 中文无码精品一区二区三区| 日韩高清不卡一区二区| 国产成人精品在线视频| 亚洲 欧美 中文字幕| 国产精品尤物| 欧美激情视频在线观看| 欧美日韩激情在线观看| 亚洲天堂男人| 久久久久久亚洲精品| 日韩欧美视频在线免费观看| 亚洲青涩在线| 8x海外华人永久免费日韩内陆视频| 青青操国产视频| 欧美成人69av| 九九九热精品免费视频观看网站| 91嫩草|国产丨精品入口| 亚洲一区欧美| 久久97精品久久久久久久不卡| 欧美激情 一区| 欧美疯狂party性派对| 久久黄色av网站| 欧美国产日韩综合| 国产精品毛片在线| 国产97在线|日韩| 做爰无遮挡三级| 国产一区二区视频在线播放| 91|九色|视频| 香蕉视频免费看| 国产亚洲一区二区三区| 亚洲综合av一区| 天堂中文а√在线| 亚洲一区二区精品久久av| 每日在线观看av| 欧美va视频| 欧美日韩视频第一区| 成人性生交视频免费观看| 国产精品毛片久久久| 日韩久久精品成人| 人人艹在线视频| 欧美三级网页| 日韩暖暖在线视频| 国产日韩在线观看一区| 成人国产精品免费观看动漫| 欧美日韩在线观看一区| 黄色网在线看| 亚洲r级在线视频| 国产欧美在线一区| 成人在线精品| 日韩精品免费在线观看| 亚洲精品自拍视频在线观看| 在线精品观看| 国产精品入口免费视频一| 亚洲精品久久久久久久久久久久久久 | 中文人妻熟女乱又乱精品| 国产精品77777竹菊影视小说| 精品欧美一区二区三区久久久 | 艳母动漫在线观看| 天堂中文最新版在线中文| 欧美精品久久99| av网页在线观看| 久久久久久美女精品| 欧美一级视频一区二区| 91在线观看喷潮| 97se亚洲国产综合自在线| 最新不卡av| 欧洲精品一区二区三区| 亚洲国产古装精品网站| 三级黄色在线观看| 视频一区视频二区在线观看| 99久热re在线精品视频| 在线视频婷婷| 色综合av在线| 欧美深性狂猛ⅹxxx深喉 | 黄色在线播放网站| 欧美色xxxx| 欧美日韩一区二区三区四区五区六区| 欧美激情777| 国产精品96久久久久久| 五月天婷婷在线播放| 亚洲大型综合色站| 国产91在线免费观看| 99视频精品全部免费在线视频| 日本a级片电影一区二区| 成人毛片在线精品国产| 一区二区三区四区激情| 不用播放器的免费av| 欧洲杯半决赛直播| 国产97免费视| 青春草在线观看| 高跟丝袜欧美一区| 69久久精品无码一区二区| 久久国产综合| 国产精品成人国产乱一区 | 午夜毛片在线观看| k8久久久一区二区三区| 男人的天堂狠狠干| 岛国精品一区| 性色av一区二区三区红粉影视| 成人午夜免费福利| 亚洲色欲色欲www在线观看| 国产又黄又猛又粗又爽的视频| 亚洲春色h网| 高清亚洲成在人网站天堂| 亚洲欧美黄色片| 亚洲午夜久久久久中文字幕久| 伊人国产精品视频| 香港欧美日韩三级黄色一级电影网站| 成人黄色激情网| 国产三级在线播放| 精品免费视频一区二区| 日本三级午夜理伦三级三| 不卡免费追剧大全电视剧网站| 欧美变态另类刺激| 日韩三级视频| 日产日韩在线亚洲欧美| 韩日视频在线| 色av一区二区| 五月激情四射婷婷| 国产综合色在线视频区| 免费看日b视频| 精品欧美午夜寂寞影院| 日韩美女毛茸茸| 91在线观看| 日韩欧美中文字幕一区| 青青草激情视频| av亚洲产国偷v产偷v自拍| 被灌满精子的波多野结衣| 欧美尿孔扩张虐视频| 国产成人精品亚洲精品| 青青草超碰在线| 欧美久久婷婷综合色| 国产在线观看免费av| 久久综合一区二区| 三级一区二区三区| 一本一本久久a久久综合精品| 99porn视频在线| 白浆在线视频| 视频一区视频二区国产精品| 亚洲国产精品久久久久久久| 欧美色道久久88综合亚洲精品| 麻豆视频免费在线播放| 成人午夜激情在线| 国产精品亚洲αv天堂无码| 国产国产精品| 91免费观看| 日产福利视频在线观看| 久久久国产一区| 黄色美女一级片| 欧美日韩在线不卡| 青青草精品毛片| 天堂av中文字幕| 欧美精品日韩精品| 波多野结衣毛片| 婷婷综合久久一区二区三区| 裸体武打性艳史| 国产精品免费看片| 国产熟妇搡bbbb搡bbbb| 成人av免费在线观看| 青青草原播放器| 老司机精品视频一区二区三区| 日本在线观看a| 亚洲国产精品一区制服丝袜| 日本成人在线不卡| 你懂的国产精品永久在线| 伊人久久99| 日韩电影免费网站| 视频一区视频二区视频三区高| 日韩av中文字幕一区| 国产精品一区二区三区精品| 欧美一区一区| 91老司机在线| 91精品一久久香蕉国产线看观看| 国产精品免费福利| 丁香婷婷久久| 国产精品视频999| 成人国产精选| 国产精品无码专区在线观看| 欧美aaaaaa| 成人网在线视频| 高清不卡一区| 97久久人人超碰caoprom欧美| 美国十次综合久久| 国产成人一区二区三区免费看| 超碰97成人| 国产在线精品一区二区三区》| 牛牛影视久久网| 美女被啪啪一区二区| 国内精品久久久久久久影视简单| 欧洲精品亚洲精品| 日本一二区不卡| 亚洲小说欧美另类激情| 午夜电影亚洲| 男女猛烈激情xx00免费视频| 国产精品免费看| 无码人妻精品一区二区三区66| 日本不卡的三区四区五区| 女同激情久久av久久| 国产很黄免费观看久久| 日本道中文字幕| 久久久久国产精品免费免费搜索| xxx在线播放| 国产精品激情偷乱一区二区∴| 亚洲女人久久久| 亚洲一区二区三区中文字幕| 99免费在线观看| 色综合咪咪久久| 一级全黄裸体免费视频| 亚洲精品在线观| 国产主播福利在线| 播播国产欧美激情| 国产白浆在线免费观看| 国产成人免费91av在线| 中文成人激情娱乐网| 国产精品二区在线观看| 亚洲另类av| 伊人色综合影院| 激情久久一区| 九九热在线免费| 国产成人一区在线| 成人精品999| 亚洲综合色在线| 中文字幕免费观看| 欧美成人女星排行榜| 免费福利在线视频| 色综合久久精品亚洲国产 | 99久久婷婷这里只有精品 | 中日韩一级黄色片| 精品人伦一区二区三区蜜桃网站 | 中文字幕在线亚洲精品| 亚洲精品日韩久久| 小明看看成人免费视频| 99精品黄色片免费大全| 国产suv精品一区二区68| 欧美日韩一区二区精品| www黄色在线观看| 这里只有精品丝袜| 成人小电影网站| 国产激情一区二区三区在线观看| 日韩欧美网站| 日本一区二区黄色| 顶级嫩模精品视频在线看| 国产精品一区二区亚洲| 一本大道久久精品懂色aⅴ | 9人人澡人人爽人人精品| 97精品在线播放| 色播五月激情综合网| 无码国产精品96久久久久| 欧美久久精品一级黑人c片| www.国产精品| 免费看成人午夜电影| 韩日视频一区| 无码人妻久久一区二区三区蜜桃| 国产精品乱子久久久久| 波多野结衣电影在线播放| 日韩经典中文字幕| 91丝袜在线| 豆国产97在线| 欧美在线播放| 色网站在线视频| 亚洲欧洲成人av每日更新| 中文在线观看免费高清| 亚洲色在线视频| 亚洲少妇视频| 久久久久久国产精品免费免费| 国产精品videossex久久发布| 色网站在线视频| 亚洲欧美一区二区三区久本道91 | 成人高清av在线| 久久精品这里只有精品| 欧美一区二视频| а√天堂8资源在线官网| 成人中文字幕在线观看| 99精品网站| 日本黄色三级网站| 亚洲乱码国产乱码精品精的特点 | 精品午夜视频| 亚洲精品国产suv一区88| 国产麻豆视频一区二区| 麻豆精品一区二区三区视频| 日韩一二在线观看| 免费在线国产视频| 成人欧美一区二区| 亚洲毛片在线| 插吧插吧综合网| 欧美在线观看视频在线| 色综合久久影院| 亚洲qvod图片区电影| 国产精品啊啊啊| 苍井空张开腿实干12次| 午夜精品久久久久久久| 三级在线电影| 国产精品91久久| 国产精品久久久久无码av| 三级av免费看| 亚洲制服丝袜一区| 亚州av在线播放| 国产精品成av人在线视午夜片| 日本在线电影一区二区三区| 91看片破解版| 亚洲动漫第一页| 九色在线免费| 亚洲资源在线看| 一本色道久久精品| 久久久久久成人网| 欧美一级xxx| 密臀av在线播放| 亚洲永久激情精品| 成人av资源网站| 免费在线不卡av| 欧美理论电影在线播放| 妖精视频一区二区三区 | 99久久精品免费| 波多野结衣黄色| 欧美激情中文字幕在线| 欧美军人男男激情gay| www.久久com| 日韩欧美a级成人黄色| 欧美18一19xxx性| 国内精品**久久毛片app| 狠狠色伊人亚洲综合成人| 日本在线观看中文字幕| 最近中文字幕2019免费| 草草视频在线一区二区| 欧美日韩中文不卡| 欧美日韩免费看| 中文字幕中文字幕在线十八区| 久久综合久久久| 国产精品一区二区在线看| 无码一区二区三区在线观看| 欧美黄色www| 日韩中文首页| 一级黄色片大全| 欧美成人a在线| 亚洲伦理网站|