• <strike id="800qq"></strike>
    <ul id="800qq"></ul>
    
    
    <ul id="800qq"><tbody id="800qq"></tbody></ul>
  • 您的位置:區域經濟 > 正文

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

    來源: 時間:2023-07-07 16:11:06

    本文樣式方案學習了 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 (              Hello world!          )  }}
    .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.scssexport 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;}中的txtconst 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。如以下示例代碼,僅類選擇器CssRuletxt被拆分了_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 }// 處理后的代碼import "./index.module.scss"Index = () => {  return }

    本樣式方案通過對僅使用了類選擇器的 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     item1    item2  }// 處理后的代碼import React from "react"import "./index.module.scss"http:// styles = {box: "_a -a", item1: "_a _b _c", item2: "_a _b _d -b"}export default Index = () => {  return     item1    item2  }
    // 原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 }

    本方案為了盡可能保證項目 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 標題}// 處理后的代碼import styles from "./index.module.scss"const Index = () => {  return 標題}
    // 原代碼.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"// 而不是import "./index.module.scss"

    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"標題

    但是在樣式文件中默認所有 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-modulescssModules插件
    關鍵詞:

    精彩推送

    公司

    一到夏天,各種“硬核防曬”成了無數年輕人熱議的話題。在戶外街頭,越

    詳細>>

    近日,第十一屆亞洲煉油和化工科技大會在山東煙臺舉行。記者在會上注意

    詳細>>

    隨著暑期來臨,多個平臺數據顯示旅游市場進一步“升溫”,在高溫天氣的

    詳細>>

    文物全科人才畢業后直接到縣(市、區)及以下文物保護事業單位定向就業

    詳細>>

    今年,鄂爾多斯立足于全市資源型缺水、水質型缺水、工程型缺水并存的實

    詳細>>

    7月5日,新鄉市農科院傳來喜訊,該院近日收到農業農村部頒發的21個植物

    詳細>>
    77777_亚洲午夜久久多人| 亚洲精品WWW久久久久久| 亚洲国产日韩成人综合天堂| 亚洲AV成人片无码网站| 亚洲av专区无码观看精品天堂| 亚洲手机中文字幕| 亚洲噜噜噜噜噜影院在线播放 | 久久精品视频亚洲| 亚洲欧洲无码AV电影在线观看 | 亚洲视频在线一区二区| 亚洲精品国产日韩无码AV永久免费网| 天天综合亚洲色在线精品| 亚洲午夜久久久影院| 亚洲国产精品综合久久一线| 亚洲成AⅤ人影院在线观看| www.亚洲色图.com| 亚洲精品无码久久毛片| 亚洲免费视频一区二区三区| 国产亚洲人成A在线V网站| 中文国产成人精品久久亚洲精品AⅤ无码精品| 亚洲伊人久久综合中文成人网| 精品国产亚洲男女在线线电影| 国产成人综合亚洲AV第一页| 亚洲精品无码久久久久去q | 亚洲男人的天堂www| 久久99国产亚洲高清观看首页| 久久综合日韩亚洲精品色| 久久精品国产亚洲av日韩| 亚洲成年人电影网站| 国产v亚洲v天堂a无| 日本亚洲欧美色视频在线播放| 国产99久久亚洲综合精品| 亚洲性日韩精品国产一区二区| 亚洲色中文字幕无码AV| 亚洲av日韩av天堂影片精品| 亚洲美女激情视频| 亚洲色中文字幕在线播放| 国产av无码专区亚洲av毛片搜| 亚洲综合伊人久久综合| 亚洲AV第一页国产精品| 亚洲第一香蕉视频|