国产熟女一区二区91,人妻少妇精品久久久久久蜜臀av,99re国产在线观看,婷婷午夜av天堂,日本东京热久久久a,日本欧美一级二级三级,欧美另类丝袜一区在线,国产精品白浆久久久久久久,久99re在线播放

【由淺入深】vue組件庫實(shí)戰(zhàn)開發(fā)總結(jié)分享-天天熱聞

來源:php中文網(wǎng) | 2022-12-27 20:01:38 |

很慶幸標(biāo)題能夠趕上2022結(jié)束的腳步。本文由淺入深層層遞進(jìn),對(duì)組件庫的開發(fā)過程做個(gè)了小結(jié)。

由于篇幅有限,陰影部分的內(nèi)容將在中/下篇介紹。

話不多說,直入主題。


【資料圖】

yarn workspace + lerna: 管理組件庫及其生態(tài)項(xiàng)目

考慮到組件庫整體需要有多邊資源支持,比如組件源碼,庫文檔站點(diǎn),color-gen等類庫工具,代碼規(guī)范配置,vite插件,腳手架,storybook等等,需要分出很多packages,package之間存在彼此聯(lián)系,因此考慮使用monorepo的管理方式,同時(shí)使用yarn作為包管理工具,lerna作為包發(fā)布工具?!鞠嚓P(guān)推薦:vuejs視頻教程、web前端開發(fā)】

在monorepo之前,根目錄就是一個(gè)workspace,我們直接通過yarn add/remove/run等就可以對(duì)包進(jìn)行管理。但在monorepo項(xiàng)目中,根目錄下存在多個(gè)子包,yarn 命令無法直接操作子包,比如根目錄下無法通過yarn run dev啟動(dòng)子包package-a中的dev命令,這時(shí)我們就需要開啟yarn的workspaces功能,每個(gè)子包對(duì)應(yīng)一個(gè)workspace,之后我們就可以通過yarn workspace package-a run dev啟動(dòng)package-a中的dev命令了。

你可能會(huì)想,我們直接cd到package-a下運(yùn)行就可以了,不錯(cuò),但yarn workspaces的用武之地并不只此,像auto link,依賴提升,單.lock等才是它在monorepo中的價(jià)值所在。

啟用yarn workspaces

我們?cè)诟夸沺ackge.json中啟用yarn workspaces:

{  "private": true,  "workspaces": [    "packages/*"  ]}

packages目錄下的每個(gè)直接子目錄作為一個(gè)workspace。由于我們的根項(xiàng)目是不需要發(fā)布出去的,因此設(shè)置private為true。

安裝lerna并初始化

不得不說,yarn workspaces已經(jīng)具備了lerna部分功能,之所以使用它,是想借用它的發(fā)布工作流以彌補(bǔ)workspaces在monorepo下在這方面的不足。下面我們開始將lerna集成到項(xiàng)目中。

首先我們先安裝一下lerna:

# W指workspace-root,即在項(xiàng)目根目錄下安裝,下同yarn add lerna -D -W# 由于經(jīng)常使用lerna命令也推薦全局安裝yarn global add lernaornpm i lerna -g

執(zhí)行lerna init初始化項(xiàng)目,成功之后會(huì)幫我們創(chuàng)建了一個(gè)lerna.json文件

lerna init
// lerna.json{  "$schema": "node_modules/lerna/schemas/lerna-schema.json",  "useWorkspaces": true,  "version": "0.0.0"}

$schema指向的lerna-schema.json描述了如何配置lerna.json,配置此字段后,鼠標(biāo)懸浮在屬性上會(huì)有對(duì)應(yīng)的描述。注意,以上的路徑值需要你在項(xiàng)目根目錄下安裝lerna。

useWorkspaces定義了在lerna bootstrap期間是否結(jié)合yarn workspace。

由于lerna默認(rèn)的工作模式是固定模式,即發(fā)布時(shí)每個(gè)包的版本號(hào)一致。這里我們修改為independent獨(dú)立模式,同時(shí)將npm客戶端設(shè)置為yarn。如果你喜歡pnpm,just do it!

// lerna.json{  "version": "independent",  "npmClient": "yarn"}

至此yarn workspaces搭配lerna的monorepo項(xiàng)目就配置好了,非常簡(jiǎn)單!

額外的lerna配置

By the way!由于項(xiàng)目會(huì)使用commitlint對(duì)提交信息進(jìn)行校驗(yàn)是否符合Argular規(guī)范,而lerna version默認(rèn)為我們commit的信息是"Publish",因此我們需要進(jìn)行一些額外的配置。

// lerna.json{  "command": {    "version": {      "message": "chore(release): publish",      "conventionalCommits": true    }  }}

可以看到,我們使用符合Argular團(tuán)隊(duì)提交規(guī)范的"chore(release): publish"代替默認(rèn)的"Publish"。

conventionalCommits表示當(dāng)我們運(yùn)行lerna version,實(shí)際上會(huì)運(yùn)行lerna version --conventional-commits幫助我們生成CHANGELOG.md。

小結(jié)

在lerna剛發(fā)布的時(shí)候,那時(shí)的包管理工具還沒有可用的workspaces解決方案,因此lerna自身實(shí)現(xiàn)了一套解決方案。時(shí)至今日,現(xiàn)代的包管理工具幾乎都內(nèi)置了workspaces功能,這使得lerna和yarn有許多功能重疊,比如執(zhí)行包pkg-a的dev命令lerna run dev --stream --scope=pkg-a,我們完全可以使用yarn workspace pkg-a run dev代替。lerna bootstrap --hoist將安裝包提升到根目錄,而在yarn workspaces中直接運(yùn)行yarn就可以了。

Anyway, 使用yarn作為軟件包管理工具,lerna作為軟件包發(fā)布工具,是在monorepo管理方式下一個(gè)不錯(cuò)的實(shí)踐!

集成Lint工具規(guī)范化代碼

很無奈,我知道大部分人都不喜歡Lint,但對(duì)我而言,這是必須的。

集成eslint

packages目錄下創(chuàng)建名為@argo-design/eslint-config(非文件夾名)的package

1. 安裝eslint

cd argo-eslint-configyarn add eslintnpx eslint --init

注意這里沒有-D或者--save-dev。選擇如下:

安裝完成后手動(dòng)將devDependencies下的依賴拷貝到dependencies中。或者你手動(dòng)安裝這一系列依賴。

2. 使用

// argo-eslint-config/package.json{  scripts: {    "lint:script": "npx eslint --ext .js,.jsx,.ts,.tsx --fix --quiet ./"  }}

運(yùn)行yarn lint:script,將會(huì)自動(dòng)修復(fù)代碼規(guī)范錯(cuò)誤警告(如果可以的話)。

3. VSCode保存時(shí)自動(dòng)修復(fù)

安裝VSCode Eslint插件并進(jìn)行如下配置,此時(shí)在你保存代碼時(shí),也會(huì)自動(dòng)修復(fù)代碼規(guī)范錯(cuò)誤警告。

// settings.json{  "editor.defaultFormatter": "dbaeumer.vscode-eslint",  "editor.codeActionsOnSave": {    "source.fixAll.eslint": true  }}

4. 集成到項(xiàng)目全局

argo-eslint-config中新建包入口文件index.js,并將.eslintrc.js的內(nèi)容拷貝到index.js中

module.exports = {  env: {    browser: true,    es2021: true,    node: true  },  extends: ["plugin:vue/vue3-essential", "standard-with-typescript"],  overrides: [],  parserOptions: {    ecmaVersion: "latest",    sourceType: "module"  },  plugins: ["vue"],  rules: {}}

確保package.json配置main指向我們剛剛創(chuàng)建的index.js。

// argo-eslint-config/package.json{   "main": "index.js"}

根目錄package.json新增如下配置

// argo-eslint-config/package.json{  "devDependencies": {    "@argo-design/eslint-config": "^1.0.0"  },  "eslintConfig": {    "root": true,    "extends": [      "@argo-design"    ]  }}

最后運(yùn)行yarn重新安裝依賴。

注意包命名與extends書寫規(guī)則;root表示根配置,對(duì)eslint配置文件冒泡查找到此為止。

集成prettier

接下來我們引入formatter工具prettier。首先我們需要關(guān)閉eslint規(guī)則中那些與prettier沖突或者不必要的規(guī)則,最后由prettier代為實(shí)現(xiàn)這些規(guī)則。前者我們通過eslint-config-prettier實(shí)現(xiàn),后者借助插件eslint-plugin-prettier實(shí)現(xiàn)。比如沖突規(guī)則尾逗號(hào),eslint-config-prettier幫我們屏蔽了與之沖突的eslint規(guī)則:

{  "comma-dangle": "off",  "no-comma-dangle": "off",  "@typescript-eslint/comma-dangle": "off",  "vue/comma-dangle": "off",}

通過配置eslint規(guī)則"prettier/prettier": "error"讓錯(cuò)誤暴露出來,這些錯(cuò)誤交給eslint-plugin-prettier收拾。

prettier配置我們也新建一個(gè)package@argo-design/prettier-config。

1. 安裝

cd argo-prettier-configyarn add prettieryarn add eslint-config-prettier eslint-plugin-prettier

2. 使用

// argo-prettier-config/index.jsmodule.exports = {  printWidth: 80, //一行的字符數(shù),如果超過會(huì)進(jìn)行換行,默認(rèn)為80  semi: false, // 行尾是否使用分號(hào),默認(rèn)為true  trailingComma: "none", // 是否使用尾逗號(hào)  bracketSpacing: true // 對(duì)象大括號(hào)直接是否有空格};

完整配置參考官網(wǎng) prettier配置

3. 配置eslint

回到argo-eslint-config/index.js,只需新增如下一條配置即可

module.exports = {   "extends": ["plugin:prettier/recommended"]};

plugin:prettier/recommended指的eslint-plugin-prettierpackage下的recommended.js。該擴(kuò)展已經(jīng)幫我們配置好了

{  "extends": ["eslint-config-prettier"],  "plugins": ["eslint-plugin-prettier"],  "rules": {    "prettier/prettier": "error",    "arrow-body-style": "off",    "prefer-arrow-callback": "off"  }}

4. 集成到項(xiàng)目全局

根目錄package.json新增如下配置

{  "devDependencies": {    "@argo-design/prettier-config": "^1.0.0"  },  "prettier": "@argo-design/prettier-config"}

運(yùn)行yarn重新安裝依賴。

5. VSCode安裝prettier擴(kuò)展并將其設(shè)置成默認(rèn)格式化工具

// settings.json{  "editor.defaultFormatter": "esbenp.prettier-vscode"}

集成stylelint

stylelint配置我們也新建一個(gè)package@argo-design/stylelint-config。

1. 安裝

cd argo-stylelint-configyarn add stylelint stylelint-prettier stylelint-config-prettier stylelint-order stylelint-config-rational-order postcss-html postcss-less# 單獨(dú)postcss8yarn add postcss@^8.0.0

對(duì)于結(jié)合prettier這里不在贅述。

stylelint-order允許我們自定義樣式屬性名稱順序。而stylelint-config-rational-order為我們提供了一套合理的開箱即用的順序。

值得注意的是,stylelint14版本不在默認(rèn)支持less,sass等預(yù)處理語言。并且stylelint14依賴postcss8版本,可能需要單獨(dú)安裝,否則vscode 的stylellint擴(kuò)展可能提示報(bào)錯(cuò)TypeError: this.getPosition is not a function at LessParser.inlineComment....

2. 使用

// argo-stylelint-config/index.jsmodule.exports = {  plugins: [    "stylelint-prettier",  ],  extends: [    // "stylelint-config-standard",    "stylelint-config-standard-vue",     "stylelint-config-rational-order",    "stylelint-prettier/recommended"  ],  rules: {    "length-zero-no-unit": true, // 值為0不需要單位    "plugin/rational-order": [      true,      {        "border-in-box-model": true, // Border理應(yīng)作為盒子模型的一部分 默認(rèn)false        "empty-line-between-groups": false // 組之間添加空行 默認(rèn)false      }    ]  },  overrides: [    {      files: ["*.html", "**/*.html"],      customSyntax: "postcss-html"    },    {      files: ["**/*.{less,css}"],      customSyntax: "postcss-less"    }  ]};

3. 集成到項(xiàng)目全局

根目錄package.json新增如下配置

{  "devDependencies": {    "@argo-design/stylelint-config": "^1.0.0"  },  "stylelint": {    "extends": [      "@argo-design/stylelint-config"    ]  }}

運(yùn)行yarn重新安裝依賴。

4. VSCode保存時(shí)自動(dòng)修復(fù)

VSCode安裝Stylelint擴(kuò)展并添加配置

// settings.json{  "editor.codeActionsOnSave": {    "source.fixAll.eslint": true,    "source.fixAll.stylelint": true  },  "stylelint.validate": ["css", "less", "vue", "html"],  "css.validate": false,  "less.validate": false}

修改settings.json之后如不能及時(shí)生效,可以重啟一下vscode。如果你喜歡,可以將eslint,prettier,stylelint配置安裝到全局并集成到編輯器。

集成husky

為防止一些非法的commitpush,我們借助git hooks工具在對(duì)代碼提交前進(jìn)行 ESLint 與 Stylelint的校驗(yàn),如果校驗(yàn)通過,則成功commit,否則取消commit。

1. 安裝

# 在根目錄安裝huskyyarn add husky -D -W

2. 使用

npm pkg set scripts.prepare="husky install"npm run prepare# 添加pre-commit鉤子,在提交前運(yùn)行代碼lintnpx husky add .husky/pre-commit "yarn lint"

至此,當(dāng)我們執(zhí)行git commit -m "xxx"時(shí)就會(huì)先執(zhí)行l(wèi)int校驗(yàn)我們的代碼,如果lint通過,成功commit,否則終止commit。具體的lint命令請(qǐng)自行添加。

集成lint-staged: 僅校驗(yàn)staged中文件

現(xiàn)在,當(dāng)我們git commit時(shí),會(huì)對(duì)整個(gè)工作區(qū)的代碼進(jìn)行l(wèi)int。當(dāng)工作區(qū)文件過多,lint的速度就會(huì)變慢,進(jìn)而影響開發(fā)體驗(yàn)。實(shí)際上我們只需要對(duì)暫存區(qū)中的文件進(jìn)行l(wèi)int即可。下面我們引入·lint-staged解決我們的問題。

1. 安裝

在根目錄安裝lint-staged

yarn add lint-staged -D -W

2. 使用

在根目錄package.json中添加如下的配置:

{  "lint-staged": {    "*.{js,ts,jsx,tsx}": [      "eslint --fix",      "prettier --write"    ],    "*.{less,css}": [      "stylelint --fix",      "prettier --write"    ],    "**/*.vue": [      "eslint --fix",      "stylelint --fix",      "prettier --write"    ]  }}

在monorepo中,lint-staged運(yùn)行時(shí),將始終向上查找并應(yīng)用最接近暫存文件的配置,因此我們可以在根目錄下的package.json中配置lint-staged。值得注意的是,每個(gè)glob匹配的數(shù)組中的命令是從左至右依次運(yùn)行,和webpack的loder應(yīng)用機(jī)制不同!

最后,我們?cè)?husky文件夾中找到pre-commit,并將yarn lint修改為npx --no-install lint-staged。

#!/usr/bin/env sh. "$(dirname -- "$0")/_/husky.sh"npx --no-install lint-staged

至此,當(dāng)我們執(zhí)行git commit -m "xxx"時(shí),lint-staged會(huì)如期運(yùn)行幫我們校驗(yàn)staged(暫存區(qū))中的代碼,避免了對(duì)工作區(qū)的全量檢查。

集成commitlint: 規(guī)范化commit message

除了代碼規(guī)范檢查之后,Git 提交信息的規(guī)范也是不容忽視的一個(gè)環(huán)節(jié),規(guī)范精準(zhǔn)的 commit 信息能夠方便自己和他人追蹤項(xiàng)目和把控進(jìn)度。這里,我們使用大名鼎鼎的Angular團(tuán)隊(duì)提交規(guī)范。

commit message格式規(guī)范

commit message 由 Header、Body、Footer組成。其中Herder時(shí)必需的,Body和Footer可選。

Header

Header 部分包括三個(gè)字段 type、scopesubject

<type>(<scope>): <subject>
type

其中type 用于說明 commit 的提交類型(必須是以下幾種之一)。

描述
featFeature) 新增一個(gè)功能
fixBug修復(fù)
docsDocumentation) 文檔相關(guān)
style代碼格式(不影響功能,例如空格、分號(hào)等格式修正),并非css樣式更改
refactor代碼重構(gòu)
perfPerforment) 性能優(yōu)化
test測(cè)試相關(guān)
build構(gòu)建相關(guān)(例如 scopes: webpack、gulp、npm 等)
ci更改持續(xù)集成軟件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等
chore變更構(gòu)建流程或輔助工具,日常事務(wù)
revertgit revert
scope

scope 用于指定本次 commit 影響的范圍。

subject

subject 是本次 commit 的簡(jiǎn)潔描述,通常遵循以下幾個(gè)規(guī)范:

用動(dòng)詞開頭,第一人稱現(xiàn)在時(shí)表述,例如:change 代替 changed 或 changes

第一個(gè)字母小寫

結(jié)尾不加句號(hào).

Body(可選)

body 是對(duì)本次 commit 的詳細(xì)描述,可以分成多行。跟 subject 類似。

Footer(可選)

如果本次提交的代碼是突破性的變更或關(guān)閉Issue,則 Footer 必需,否則可以省略。

集成commitizen(可選)

我們可以借助工具幫我們生成規(guī)范的message。

1. 安裝

yarn add commitizen -D -W

2. 使用

安裝適配器

yarn add cz-conventional-changelog -D -W

這行命令做了兩件事:

安裝cz-conventional-changelog到開發(fā)依賴

在根目錄下的package.json中增加了:

"config": {  "commitizen": {    "path": "./node_modules/cz-conventional-changelog"  }}

添加npm scriptscm

"scripts": {  "cm": "cz"},

至此,執(zhí)行yarn cm,就能看到交互界面了!跟著交互一步步操作就能自動(dòng)生成規(guī)范的message了。

集成commitlint: 對(duì)最終提交的message進(jìn)行校驗(yàn)

1. 安裝

首先在根目錄安裝依賴:

yarn add commitlint @commitlint/cli @commitlint/config-conventional -D -W

2. 使用

接著新建.commitlintrc.js:

module.exports = {  extends: ["@commitlint/config-conventional"]};

最后向husky中添加commit-msg鉤子,終端執(zhí)行:

npx husky add .husky/commit-msg "npx --no-install commitlint -e $HUSKY_GIT_PARAMS"

執(zhí)行成功之后就會(huì)在.husky文件夾中看到commit-msg文件了:

#!/usr/bin/env sh. "$(dirname -- "$0")/_/husky.sh"npx --no-install commitlint -e

至此,當(dāng)你提交代碼時(shí),如果pre-commit鉤子運(yùn)行成功,緊接著在commit-msg鉤子中,commitlint會(huì)如期運(yùn)行對(duì)我們提交的message進(jìn)行校驗(yàn)。

關(guān)于lint工具的集成到此就告一段落了,在實(shí)際開發(fā)中,我們還會(huì)對(duì)lint配置進(jìn)行一些小改動(dòng),比如ignore,相關(guān)rules等等。這些和具體項(xiàng)目有關(guān),我們不會(huì)變更package里的配置。

千萬別投機(jī)取巧拷貝別人的配置文件!復(fù)制一時(shí)爽,代碼火葬場(chǎng)。

圖標(biāo)庫

巧婦難為無米之炊。組件庫通常依賴很多圖標(biāo),因此我們先開發(fā)一個(gè)支持按需引入的圖標(biāo)庫。

假設(shè)我們現(xiàn)在已經(jīng)拿到了一些漂亮的svg圖標(biāo),我們要做的就是將每一個(gè)圖標(biāo)轉(zhuǎn)化生成.vue組件與一個(gè)組件入口index.ts文件。然后再生成匯總所有組件的入口文件。比如我們現(xiàn)在有foo.svg與bar.svg兩個(gè)圖標(biāo),最終生成的文件及結(jié)構(gòu)如下:

相應(yīng)的內(nèi)容如下:

// bar.tsimport _Bar from "./bar.vue";const Bar = Object.assign(_Bar, {  install: (app) => {    app.component(_Bar.name, _Bar);  }});export default Bar;
// foo.tsimport _Foo from "./foo.vue";const Foo = Object.assign(_Foo, {  install: (app) => {    app.component(_Foo.name, _Foo);  }});export default Foo;
// argoIcon.tsimport Foo from "./foo";import Bar from "./bar";const icons = [Foo, Bar];const install = (app) => {  for (const key of Object.keys(icons)) {    app.use(icons[key]);  }};const ArgoIcon = {  ...icons,  install};export default ArgoIcon;
// index.tsexport { default } from "./argoIcon";export { default as Foo } from "./foo";export { default as Bar } from "./bar";

之所以這么設(shè)計(jì)是由圖標(biāo)庫最終如何使用決定的,除此之外argoIcon.ts也將會(huì)是打包umd的入口文件。

// 全量引入import ArgoIcon from "圖標(biāo)庫";app.use(ArgoIcon); // 按需引入import { Foo } from "圖標(biāo)庫";app.use(Foo);

圖標(biāo)庫的整個(gè)構(gòu)建流程大概分為以下3步:

1. svg圖片轉(zhuǎn).vue文件

整個(gè)流程很簡(jiǎn)單,我們通過glob匹配到.svg拿到所有svg的路徑,對(duì)于每一個(gè)路徑,我們讀取svg的原始文本信息交由第三方庫svgo處理,期間包括刪除無用代碼,壓縮,自定義屬性等,其中最重要的是為svg標(biāo)簽注入我們想要的自定義屬性,就像這樣:

<svg   :class="cls"   :style="innerStyle"  :stroke-linecap="strokeLinecap"  :stroke-linejoin="strokeLinejoin"  :stroke-width="strokeWidth">  <path d="..."></path></svg>

之后這段svgHtml會(huì)傳送給我們預(yù)先準(zhǔn)備好的摸板字符串:

const template = `<template>  ${svgHtml}</template><script setup>defineProps({    "stroke-linecap": String;    // ...  })  // 省略邏輯代碼...</script>`

為摸板字符串填充數(shù)據(jù)后,通過fs模塊的writeFile生成我們想要的.vue文件。

2. 打包vue組件

在打包構(gòu)建方案上直接選擇vite為我們提供的lib模式即可,開箱即用,插件擴(kuò)展(后面會(huì)講到),基于rollup,能幫助我們打包生成ESM,這是按需引入的基礎(chǔ)。當(dāng)然,commonjsumd也是少不了的。整個(gè)過程我們通過Vite 的JavaScript API實(shí)現(xiàn):

import { build } from "vite";import fs from "fs-extra";const CWD = process.cwd();const ES_DIR = resolve(CWD, "es");const LIB_DIR = resolve(CWD, "lib");interface compileOptions {  umd: boolean;  target: "component" | "icon";}async function compileComponent({  umd = false,  target = "component"}: compileOptions): Promise<void> {  await fs.emptyDir(ES_DIR);  await fs.emptyDir(LIB_DIR);  const config = getModuleConfig(target);  await build(config);  if (umd) {    await fs.emptyDir(DIST_DIR);    const umdConfig = getUmdConfig(target);    await build(umdConfig);  }}
import { InlineConfig } from "vite";import glob from "glob";const langFiles = glob.sync("components/locale/lang/*.ts");export default function getModuleConfig(type: "component" | "icon"): InlineConfig {  const entry = "components/index.ts";  const input = type === "component" ? [entry, ...langFiles] : entry;  return {    mode: "production",    build: {      emptyOutDir: true,      minify: false,      brotliSize: false,      rollupOptions: {        input,        output: [          {            format: "es", // 打包模式            dir: "es", // 產(chǎn)物存放路徑            entryFileNames: "[name].js", // 入口模塊的產(chǎn)物文件名            preserveModules: true, // 保留模塊結(jié)構(gòu),否則所有模塊都將打包在一個(gè)bundle文件中            /*             * 保留模塊的根路徑,該值會(huì)在打包后的output.dir中被移除             * 我們的入口是components/index.ts,打包后文件結(jié)構(gòu)為:es/components/index.js             * preserveModulesRoot設(shè)為"components",打包后就是:es/index.js            */            preserveModulesRoot: "components"           },          {            format: "commonjs",            dir: "lib",            entryFileNames: "[name].js",            preserveModules: true,            preserveModulesRoot: "components",            exports: "named" // 導(dǎo)出模式          }        ]      },      // 開啟lib模式      lib: {        entry,        formats: ["es", "cjs"]      }    },    plugins: [      // 自定義external忽略node_modules      external(),      // 打包聲明文件      dts({        outputDir: "es",        entryRoot: C_DIR      })    ]  };};
export default function getUmdConfig(type: "component" | "icon"): InlineConfig {  const entry =    type === "component"      ? "components/argo-components.ts"      : "components/argo-icons.ts";  const entryFileName = type === "component" ? "argo" : "argo-icon";  const name = type === "component" ? "Argo" : "ArgoIcon";  return {    mode: "production",    build: {      target: "modules", // 支持原生 ES 模塊的瀏覽器      outDir: "dist", // 打包產(chǎn)物存放路徑      emptyOutDir: true, // 如果outDir在根目錄下,則清空outDir      sourcemap: true, // 生成sourcemap       minify: false, // 是否壓縮      brotliSize: false, // 禁用 brotli 壓縮大小報(bào)告。      rollupOptions: { // rollup打包選項(xiàng)        external: "vue", // 匹配到的模塊不會(huì)被打包到bundle        output: [          {            format: "umd", // umd格式            entryFileNames: `${entryFileName}.js`, // 即bundle名            globals: {              /*               * format為umd/iife時(shí),標(biāo)記外部依賴vue,打包后以Vue取代               * 未定義時(shí)打包結(jié)果如下               * var ArgoIcon = function(vue2) {}(vue);               * rollup自動(dòng)猜測(cè)是vue,但實(shí)際是Vue.這會(huì)導(dǎo)致報(bào)錯(cuò)               * 定義后               * var ArgoIcon = function(vue) {}(Vue);              */              vue: "Vue"            }          },          {            format: "umd",            entryFileNames: `${entryFileName}.min.js`,            globals: {              vue: "Vue"            },            plugins: [terser()] // terser壓縮          },        ]      },      // 開啟lib模式      lib: {        entry, // 打包入口        name // 全局變量名      }    },    plugins: [vue(), vueJsx()]  };};
export const CWD = process.cwd();export const C_DIR = resolve(CWD, "components");

可以看到,我們通過type區(qū)分組件庫和圖標(biāo)庫打包。實(shí)際上打包圖標(biāo)庫和組件庫都是差不多的,組件庫需要額外打包國(guó)際化相關(guān)的語言包文件。圖標(biāo)樣式內(nèi)置在組件之中,因此也不需要額外打包。

3. 打包聲明文件

我們直接通過第三方庫 vite-plugin-dts 打包圖標(biāo)庫的聲明文件。

import dts from "vite-plugin-dts";plugins: [  dts({    outputDir: "es",    entryRoot: C_DIR  })]

關(guān)于打包原理可參考插件作者的這片文章。

lequ7.com/guan-yu-qia…

4. 實(shí)現(xiàn)按需引入

我們都知道實(shí)現(xiàn)tree-shaking的一種方式是基于ESM的靜態(tài)性,即在編譯的時(shí)候就能摸清依賴之間的關(guān)系,對(duì)于"孤兒"會(huì)殘忍的移除。但是對(duì)于import "icon.css"這種沒導(dǎo)入導(dǎo)出的模塊,打包工具并不知道它是否具有副作用,索性移除,這樣就導(dǎo)致頁面缺少樣式了。sideEffects就是npm與構(gòu)建工具聯(lián)合推出的一個(gè)字段,旨在幫助構(gòu)建工具更好的為npm包進(jìn)行tree-shaking。

使用上,sideEffects設(shè)置為false表示所有模塊都沒有副作用,也可以設(shè)置數(shù)組,每一項(xiàng)可以是具體的模塊名或Glob匹配。因此,實(shí)現(xiàn)圖標(biāo)庫的按需引入,只需要在argo-icons項(xiàng)目下的package.json里添加以下配置即可:

{  "sideEffects": false,}

這將告訴構(gòu)建工具,圖標(biāo)庫沒有任何副作用,一切沒有被引入的代碼或模塊都將被移除。前提是你使用的是ESM。

指定入口

Last but important!當(dāng)圖標(biāo)庫在被作為npm包導(dǎo)入時(shí),我們需要在package.json為其配置相應(yīng)的入口文件。

{  "main": "lib/index.js", // 以esm形式被引入時(shí)的入口  "module": "es/index.js", // 以commonjs形式被引入時(shí)的入口  "types": "es/index.d.ts" // 指定聲明文件}

引入storybook:是時(shí)候預(yù)覽我們的成果了!

顧名思義,storybook就是一本"書",講了很多個(gè)"故事"。在這里,"書"就是argo-icons,我為它講了3個(gè)故事:

基本使用

按需引入

使用iconfont.cn項(xiàng)目

初始化storybook

新建@argo-design/ui-storybookpackage,并在該目錄下運(yùn)行:

npx storybook init -t vue3 -b webpack5

-t (即--type): 指定項(xiàng)目類型,storybook會(huì)根據(jù)項(xiàng)目依賴及配置文件等推算項(xiàng)目類型,但顯然我們僅僅是通過npm init新創(chuàng)建的項(xiàng)目,storybook無法自動(dòng)判斷項(xiàng)目類型,故需要指定type為vue3,然后storybook會(huì)幫我們初始化storybook vue3 app。

-b (--builder): 指定構(gòu)建工具,默認(rèn)是webpack4,另外支持webpack5, vite。這里指定webpack5,否則后續(xù)會(huì)有類似報(bào)錯(cuò):cannot read property of undefine(reading "get")...因?yàn)閟torybook默認(rèn)以webpack4構(gòu)建,但是@storybook/vue3依賴webpack5,會(huì)沖突導(dǎo)致報(bào)錯(cuò)。這里是天坑!!

storybook默認(rèn)使用yarn安裝,如需指定npm請(qǐng)使用--use-npm。

這行命令主要幫我們做以下事情:

注入必要的依賴到packages.json(如若沒有指定-s,將幫我們自動(dòng)安裝依賴)。

注入啟動(dòng),打包項(xiàng)目的腳本。

添加Storybook配置,詳見.storybook目錄。

添加Story范例文件以幫助我們上手,詳見stories目錄。

其中1,2步具體代碼如下:

{  "scripts": {    "storybook": "start-storybook -p 6006",    "build-storybook": "build-storybook"  },  "devDependencies": {    "@storybook/vue3": "^6.5.13",    "@storybook/addon-links": "^6.5.13",    "@storybook/addon-essentials": "^6.5.13",    "@storybook/addon-actions": "^6.5.13",    "@storybook/addon-interactions": "^6.5.13",    "@storybook/testing-library": "^0.0.13",    "vue-loader": "^16.8.3",    "@storybook/builder-webpack5": "^6.5.13",    "@storybook/manager-webpack5": "^6.5.13",    "@babel/core": "^7.19.6",    "babel-loader": "^8.2.5"  }}

接下來把目光放到.storybook下的main.js與preview.js

preview.js

preview.js可以具名導(dǎo)出parameters,decorators,argTypes,用于全局配置UI(stories,界面,控件等)的渲染行為。比如默認(rèn)配置中的controls.matchers:

export const parameters = {  controls: {    matchers: {      color: /(background|color)$/i,      date: /Date$/    }  }};

它定義了如果屬性值是以background或color結(jié)尾,那么將為其啟用color控件,我們可以選擇或輸入顏色值,date同理。

除此之外你可以在這里引入全局樣式,注冊(cè)組件等等。更多詳情見官網(wǎng) Configure story rendering

main.js

最后來看看最重要的項(xiàng)目配置文件。

module.exports = {  stories: [    "../stories/**/*.stories.mdx",    "../stories/**/*.stories.@(js|jsx|ts|tsx)"  ],  addons: [    "@storybook/addon-links",    "@storybook/addon-essentials",    "@storybook/addon-interactions"  ],  framework: "@storybook/vue3",  core: {    builder: "@storybook/builder-webpack5"  },}

stories, 即查找stroy文件的Glob。

addons, 配置需要的擴(kuò)展。慶幸的是,當(dāng)前一些重要的擴(kuò)展都已經(jīng)集成到@storybook/addon-essentials。

framework和core即是我們初識(shí)化傳遞的-t vue3 -b webpack5。

更多詳情見官網(wǎng) Configure your Storybook project

配置并啟動(dòng)storybook

less配置

由于項(xiàng)目使用到less因此我們需要配置一下less,安裝less以及相關(guān)loader。來到.storybook/main.js

module.exports = {  webpackFinal: (config) => {    config.module.rules.push({      test: /.less$/,      use: [        {          loader: "style-loader"        },        {          loader: "css-loader"        },        {          loader: "less-loader",          options: {            lessOptions: {              javascriptEnabled: true            }          }        }      ]    });    return config;  },}

配置JSX

storybook默認(rèn)支持解析jsx/tsx,但你如果需要使用jsx書寫vue3的stories,仍需要安裝相關(guān)插件。

在argo-ui-storybook下安裝 @vue/babel-plugin-jsx

yarn add @vue/babel-plugin-jsx -D

新建.babelrc

{  "plugins": ["@vue/babel-plugin-jsx"]}

關(guān)于如何書寫story,篇幅受限,請(qǐng)自行查閱范例文件或官網(wǎng)。

配置完后終端執(zhí)行yarn storybook即可啟動(dòng)我們的項(xiàng)目,辛苦的成果也將躍然紙上。

對(duì)于UI,在我們的組件庫逐漸豐富之后,將會(huì)自建一個(gè)獨(dú)具組件庫風(fēng)格的文檔站點(diǎn),拭目以待。

組件庫

組件通信

在Vue2時(shí)代,組件跨層級(jí)通信方式可謂“百花齊放”,provide/inject就是其中一種。時(shí)至今日,在composition,es6,ts加持下,provide/inject可以更加大展身手。

provide/inject原理

在創(chuàng)建組件實(shí)例時(shí),會(huì)在自身掛載一個(gè)provides對(duì)象,默認(rèn)指向父實(shí)例的provides。

const instance = {  provides: parent ? parent.provides : Object.create(appContext.provides)}

appContext.provides即createApp創(chuàng)建的app的provides屬性,默認(rèn)是null

在自身需要為子組件供數(shù)據(jù)時(shí),即調(diào)用provide()時(shí),會(huì)創(chuàng)建一個(gè)新對(duì)象,該對(duì)象的原型指向父實(shí)例的provides,同時(shí)將provide提供的選項(xiàng)添加到新對(duì)象上,這個(gè)新對(duì)象就是實(shí)例新的provides值。代碼簡(jiǎn)化就是

function provide(key, value) {   const parentProvides = currentInstance.parent && currentInstance.parent.provides;   const newObj = Object.create(parentProvides);  currentInstance.provides = newObj;  newObj[key] = value;}

而inject的實(shí)現(xiàn)原理則時(shí)通過key去查找祖先provides對(duì)應(yīng)的值:

function inject(key, defaultValue) {   const instance = currentInstance;   const provides = instance.parent == null    ? instance.vnode.appContent && instance.vnode.appContent.provides    :instance.parent.provides;  if(provides && key in provides) {    return provides[key]  }}

你可能會(huì)疑惑,為什么這里是直接去查父組件,而不是先查自身實(shí)例的provides呢?前面不是說實(shí)例的provides默認(rèn)指向父實(shí)例的provides么。但是請(qǐng)注意,是“默認(rèn)”。如果當(dāng)前實(shí)例執(zhí)行了provide()是不是把instance.provides“污染”了呢?這時(shí)再執(zhí)行inject(key),如果provide(key)的key與你inject的key一致,就從當(dāng)前實(shí)例provides取key對(duì)應(yīng)的值了,而不是取父實(shí)例的provides!

最后,我畫了2張圖幫助大家理解

新增button組件并完成打包

篇幅有限,本文不會(huì)對(duì)組件的具體實(shí)現(xiàn)講解哦,簡(jiǎn)單介紹下文件

__demo__組件使用事例constants.ts定義的常量context.ts上下文相關(guān)interface.ts組件接口TEMPLATE.md用于生成README.md的模版button/style下存放組件樣式style下存放全局樣式

打包esm與commonjs模塊

關(guān)于打包組件的esmcommonjs模塊在之前打包圖標(biāo)庫章節(jié)已經(jīng)做了介紹,這里不再贅述。

打包樣式

相對(duì)于圖標(biāo)庫,組件庫的打包需要額外打包樣式文件,大概流程如下:

生成總?cè)肟赾omponents/index.less并編譯成css。

編譯組件less。

生成dist下的argo.css與argo.min.css。

構(gòu)建組件style/index.ts。

1. 生成總?cè)肟赾omponents/index.less

import path from "path";import { outputFileSync } from "fs-extra";import glob from "glob";export const CWD = process.cwd();export const C_DIR = path.resolve(CWD, "components");export const lessgen = async () => {  let lessContent = `@import "./style/index.less";\n`; // 全局樣式文件  const lessFiles = glob.sync("**/style/index.less", {    cwd: C_DIR,    ignore: ["style/index.less"]  });  lessFiles.forEach((value) => {    lessContent += `@import "./${value}";\n`;  });  outputFileSync(path.resolve(C_DIR, "index.less"), lessContent);  log.success("genless", "generate index.less success!");};

代碼很簡(jiǎn)單,值得一提就是為什么不將lessContent初始化為空,glob中將ignore移除,這不是更簡(jiǎn)潔嗎。這是因?yàn)閟tyle/index.less作為全局樣式,我希望它在引用的最頂部。最終將會(huì)在components目錄下生成index.less內(nèi)容如下:

@import "./style/index.less";@import "./button/style/index.less";/* other less of components */

2. 打包組件樣式

import path from "path";import { readFile, copySync } from "fs-extra"import { render } from "less";export const ES_DIR = path.resolve(CWD, "es");export const LIB_DIR = path.resolve(CWD, "lib");const less2css = (lessPath: string): string => {  const source = await readFile(lessPath, "utf-8");  const { css } = await render(source, { filename: lessPath });  return css;}const files = glob.sync("**/*.{less,js}", {  cwd: C_DIR});for (const filename of files) {  const lessPath = path.resolve(C_DIR, `${filename}`);  // less文件拷貝到es和lib相對(duì)應(yīng)目錄下  copySync(lessPath, path.resolve(ES_DIR, `${filename}`));  copySync(lessPath, path.resolve(LIB_DIR, `${filename}`));  // 組件樣式/總?cè)肟谖募?全局樣式的入口文件編譯成css  if (/index.less$/.test(filename)) {    const cssFilename = filename.replace(".less", ".css");    const ES_DEST = path.resolve(ES_DIR, `${cssFilename}`);    const LIB_DEST = path.resolve(LIB_DIR, `${cssFilename}`);    const css = await less2css(lessPath);    writeFileSync(ES_DEST, css, "utf-8");    writeFileSync(LIB_DEST, css, "utf-8");  }}

3. 生成dist下的argo.css與argo.min.css

import path from "path";import CleanCSS, { Output } from "clean-css";import { ensureDirSync } from "fs-extra";export const DIST_DIR = path.resolve(CWD, "dist");console.log("start build components/index.less to dist/argo(.min).css");const indexCssPath = path.resolve(ES_DIR, "index.css");const css = readFileSync(indexCssPath, "utf8");const minContent: Output = new CleanCSS().minify(css);ensureDirSync(DIST_DIR);writeFileSync(path.resolve("dist/argo.css"), css);writeFileSync(path.resolve("dist/argo.min.css"), minContent.styles);log.success(`build components/index.less to dist/argo(.min).css`);

其中最重要的就是使用clean-css壓縮css。

4. 構(gòu)建組件style/index.ts

如果你使用過babel-plugin-import,那一定熟悉這項(xiàng)配置:

["import", { "libraryName": "antd", "style": true }]: import js and css modularly (LESS/Sass source files)["import", { "libraryName": "antd", "style": "css" }]: import js and css modularly (css built files)

通過指定style: true,babel-plugin-import可以幫助我們自動(dòng)引入組件的less文件,如果你擔(dān)心less文件定義的變量會(huì)被覆蓋或沖突,可以指定"css",即可引入組件的css文件樣式。

這一步就是要接入這點(diǎn)。但目前不是很必要,且涉及到vite插件開發(fā),暫可略過,后面會(huì)講。

來看看最終實(shí)現(xiàn)的樣子。

其中button/style/index.js內(nèi)容也就是導(dǎo)入less:

import "../../style/index.less";import "./index.less";

button/style/css.js內(nèi)容也就是導(dǎo)入css:

import "../../style/index.css";import "./index.css";

最后你可能會(huì)好奇,諸如上面提及的compileComponentcompileStyle等函數(shù)是如何被調(diào)度使用的,這其實(shí)都?xì)w功于腳手架@argo-design/scripts。當(dāng)它作為依賴被安裝到項(xiàng)目中時(shí),會(huì)為我們提供諸多命令如argo-scripts genicon,argo-scripts compileComponent等,這些函數(shù)都在執(zhí)行命令時(shí)被調(diào)用。

配置sideEffects

"sideEffects": [  "dist/*",  "es/**/style/*",  "lib/**/style/*",  "*.less"]

國(guó)際化

基本實(shí)現(xiàn)

// locale.tsimport { ref, reactive, computed, inject } from "vue";import { isString } from "../_utils/is";import zhCN from "./lang/zh-cn";export interface ArgoLang {  locale: string;  button: {    defaultText: string;  }}type ArgoI18nMessages = Record<string, ArgoLang>;// 默認(rèn)使用中文const LOCALE = ref("zh-CN");const I18N_MESSAGES = reactive<ArgoI18nMessages>({  "zh-CN": zhCN});// 添加語言包export const addI18nMessages = (  messages: ArgoI18nMessages,  options?: {    overwrite?: boolean;  }) => {  for (const key of Object.keys(messages)) {    if (!I18N_MESSAGES[key] || options?.overwrite) {      I18N_MESSAGES[key] = messages[key];    }  }};// 切換語言包export const useLocale = (locale: string) => {  if (!I18N_MESSAGES[locale]) {    console.warn(`use ${locale} failed! Please add ${locale} first`);    return;  }  LOCALE.value = locale;};// 獲取當(dāng)前語言export const getLocale = () => {  return LOCALE.value;};export const useI18n = () => {  const i18nMessage = computed<ArgoLang>(() => I18N_MESSAGES[LOCALE.value]);  const locale = computed(() => i18nMessage.value.locale);  const transform = (key: string): string => {    const keyArray = key.split(".");    let temp: any = i18nMessage.value;    for (const keyItem of keyArray) {      if (!temp[keyItem]) {        return key;      }      temp = temp[keyItem];    }    return temp;  };  return {    locale,    t: transform  };};

添加需要支持的語言包,這里默認(rèn)支持中文和英文。

// lang/zh-CN.tsconst lang: ArgoLang = {  locale: "zh-CN",  button: {    defaultText: "按鈕"  },}
// lang/en-US.tsconst lang: ArgoLang = {  locale: "en-US",  button: {    defaultText: "Button",  },}

button組件中接入

<template>  <button>    <slot> {{ t("button.defaultText") }} </slot>  </button></template><script>import { defineComponent } from "vue";import { useI18n } from "../locale";export default defineComponent({  name: "Button",  setup(props, { emit }) {    const { t } = useI18n();    return {      t    };  }});</script>

Button的國(guó)際化僅做演示,實(shí)際上國(guó)際化在日期日歷等組件中才有用武之地。

國(guó)際化演示

argo-ui-storybook/stories中添加locale.stories.ts

import { computed } from "vue";import { Meta, StoryFn } from "@storybook/vue3";import {  Button,  addI18nMessages,  useLocale,  getLocale} from "@argo-design/argo-ui/components/index"; // 源文件形式引入方便開發(fā)時(shí)調(diào)試import enUS from "@argo-design/argo-ui/components/locale/lang/en-us";interface Args {}export default {  title: "Component/locale",  argTypes: {}} as Meta<Args>;const BasicTemplate: StoryFn<Args> = (args) => {  return {    components: { Button },    setup() {      addI18nMessages({ "en-US": enUS });      const currentLang = computed(() => getLocale());      const changeLang = () => {        const lang = getLocale();        if (lang === "en-US") {          useLocale("zh-CN");        } else {          useLocale("en-US");        }      };      return { args, changeLang, currentLang };    },    template: `      <h1>內(nèi)部切換語言,當(dāng)前語言: {{currentLang}}</h1>      <p>僅在未提供ConfigProvider時(shí)生效</p>      <Button type="primary" @click="changeLang">點(diǎn)擊切換語言</Button>      <Button long style="marginTop: 20px;"></Button>    `  };};export const Basic = BasicTemplate.bind({});Basic.storyName = "基本使用";Basic.args = {};

.preview.js中全局引入組件庫樣式

import "@argo-design/argo-ui/components/index.less";

終端啟動(dòng)項(xiàng)目就可以看到效果了。

實(shí)現(xiàn)config-provider組件

通常組件庫都會(huì)提供config-provider組件來使用國(guó)際化,就像下面這樣

<template>  <a-config-provider :locale="enUS">    <a-button />  </a-config-provider></template>

下面我們來實(shí)現(xiàn)一下config-provider組件:

<template>  <slot /></template><script>import type { PropType } from "vue";import {  defineComponent,  provide,  reactive,  toRefs,} from "vue";import { configProviderInjectionKey } from "./context";export default defineComponent({  name: "ConfigProvider",  props: {    locale: {      type: Object as PropType<ArgoLang>    },  },  setup(props, { slots }) {    const { locale } = toRefs(props);    const config = reactive({      locale,    });    provide(configProviderInjectionKey, config);  }});</script>
export interface ConfigProvider {  locale?: ArgoLang;}export const configProviderInjectionKey: InjectionKey<ConfigProvider> =  Symbol("ArgoConfigProvider");

修改locale/index.ts中計(jì)算屬性i18nMessage的獲取邏輯

import { configProviderInjectionKey } from "../config-provider/context";export const useI18n = () => {  const configProvider = inject(configProviderInjectionKey, undefined);  const i18nMessage = computed<ArgoLang>(    () => configProvider?.locale ?? I18N_MESSAGES[LOCALE.value]  );  const locale = computed(() => i18nMessage.value.locale);  const transform = (key: string): string => {    const keyArray = key.split(".");    let temp: any = i18nMessage.value;    for (const keyItem of keyArray) {      if (!temp[keyItem]) {        return key;      }      temp = temp[keyItem];    }    return temp;  };  return {    locale,    t: transform  };};

編寫stories驗(yàn)證一下:

const ProviderTemplate: StoryFn<Args> = (args) => {  return {    components: { Button, ConfigProvider },    render() {      return (        <ConfigProvider {...args}>          <Button long={true} />        </ConfigProvider>      );    }  };};export const Provider = ProviderTemplate.bind({});Provider.storyName = "在config-provider中使用";Provider.args = {  // 在這里把enUS傳給ConfigProvider的locale  locale: enUS};

以上stories使用到了jsx,請(qǐng)確保安裝并配置了@vue/babel-plugin-jsx

可以看到,Button默認(rèn)是英文的,表單控件也接收到enUS語言包了,符合預(yù)期。

自動(dòng)引入組件樣式

值得注意的是,上面提到的按需引入只是引入了組件js邏輯代碼,但對(duì)于樣式依然沒有引入。

下面我們通過開發(fā)vite插件vite-plugin-auto-import-style,讓組件庫可以自動(dòng)引入組件樣式。

效果演示

現(xiàn)在我們書寫的代碼如下,現(xiàn)在我們已經(jīng)知道了,這樣僅僅是加載了組件而已。

import { createApp } from "vue";import App from "./App.vue";import { Button, Empty, ConfigProvider } from "@argo-design/argo-ui";import { Anchor } from "@argo-design/argo-ui";createApp(App)  .use(Button)  .use(Empty)  .use(ConfigProvider)  .use(Anchor)  .mount("#root");

添加插件之前:

添加插件之后:

import { defineConfig } from "vite";import argoAutoInjectStyle from "vite-plugin-argo-auto-inject-style";export default defineConfig({  plugins: [      argoAutoInjectStyle({            libs: [        {                  libraryName: "@argo-design/argo-ui",                            resolveStyle: (name) => {                              return `@argo-design/argo-ui/es/${name}/style/index.js`;          }        }      ]    })  ]})

插件實(shí)現(xiàn)

實(shí)踐之前瀏覽一遍官網(wǎng)插件介紹是個(gè)不錯(cuò)的選擇。插件API

vite插件是一個(gè)對(duì)象,通常由name和一系列鉤子函數(shù)組成:

{  name: "vite-plugin-vue-auto-inject-style",  configResolved(config) {}}

常用鉤子

config

vite.config.ts被解析完成后觸發(fā)。常用于擴(kuò)展配置??梢灾苯釉赾onfig上定義或返回一個(gè)對(duì)象,該對(duì)象會(huì)嘗試與配置文件vite.config.ts中導(dǎo)出的配置對(duì)象深度合并。

configResolved

在解析完所有配置時(shí)觸發(fā)。形參config表示最終確定的配置對(duì)象。通常將該配置保存起來在有需要時(shí)提供給其它鉤子使用。

resolveId

開發(fā)階段每個(gè)傳入模塊請(qǐng)求時(shí)被調(diào)用,常用于解析模塊路徑。返回string或?qū)ο髮⒔K止后續(xù)插件的resolveId鉤子執(zhí)行。

load

resolveId之后調(diào)用,可自定義模塊加載內(nèi)容

transform

load之后調(diào)用,可自定義修改模塊內(nèi)容。這是一個(gè)串行鉤子,即多個(gè)插件實(shí)現(xiàn)了這個(gè)鉤子,下個(gè)插件的transform需要等待上個(gè)插件的transform鉤子執(zhí)行完畢。上個(gè)transform返回的內(nèi)容將傳給下個(gè)transform鉤子。

為了讓插件完成自動(dòng)引入組件樣式,我們需要完成如下工作:

過濾出我們想要的文件。

對(duì)文件內(nèi)容進(jìn)行AST解析,將符合條件的import語句提取出來。

然后解析出具體import的組件。

最后根據(jù)組件查找到樣式文件路徑,生成導(dǎo)入樣式的語句字符串追加到import語句后面即可。

其中過濾我們使用rollup提供的工具函數(shù)createFilter;

AST解析借助es-module-lexer,非常出名,千萬級(jí)周下載量。

import type { Plugin } from "vite";import { createFilter } from "@rollup/pluginutils";import { ExportSpecifier, ImportSpecifier, init, parse } from "es-module-lexer";import MagicString from "magic-string";import * as changeCase from "change-case";import { Lib, VitePluginOptions } from "./types";const asRE = /\s+as\s+\w+,?/g;// 插件本質(zhì)是一個(gè)對(duì)象,但為了接受在配置時(shí)傳遞的參數(shù),我們通常在一個(gè)函數(shù)中將其返回。// 插件默認(rèn)開發(fā)和構(gòu)建階段都會(huì)應(yīng)用export default function(options: VitePluginOptions): Plugin {  const {    libs,    include = ["**/*.vue", "**/*.ts", "**/*.tsx"],    exclude = "node_modules/**"  } = options;  const filter = createFilter(include, exclude);  return {    name: "vite:argo-auto-inject-style",    async transform(code: string, id: string) {      if (!filter(id) || !code || !needTransform(code, libs)) {        return null;      }      await init;      let imports: readonly ImportSpecifier[] = [];      imports = parse(code)[0];        if (!imports.length) {        return null;      }      let s: MagicString | undefined;      const str = () => s || (s = new MagicString(code));      for (let index = 0; index < imports.length; index++) {        // ss import語句開始索引        // se import語句介結(jié)束索引        const { n: moduleName, se, ss } = imports[index];        if (!moduleName) continue;        const lib = getLib(moduleName, libs);        if (!lib) continue;        // 整條import語句        const importStr = code.slice(ss, se);         // 拿到每條import語句導(dǎo)入的組件集合        const importItems = getImportItems(importStr);        let endIndex = se + 1;        for (const item of importItems) {          const componentName = item.n;          const paramName = changeCase.paramCase(componentName);          const cssImportStr = `\nimport "${lib.resolveStyle(paramName)}";`;          str().appendRight(endIndex, cssImportStr);        }      }      return {        code: str().toString()      };    }  };}export type { Lib, VitePluginOptions };function getLib(libraryName: string, libs: Lib[]) {  return libs.find((item) => item.libraryName === libraryName);}function getImportItems(importStr: string) {  if (!importStr) {    return [];  }  const matchItem = importStr.match(/{(.+?)}/gs);  const formItem = importStr.match(/from.+/gs);  if (!matchItem) return [];  const exportStr = `export ${matchItem[0].replace(asRE, ",")} ${formItem}`;  let importItems: readonly ExportSpecifier[] = [];  try {    importItems = parse(exportStr)[1];  } catch (error) {    console.log(error);  }  return importItems;}function needTransform(code: string, libs: Lib[]) {  return libs.some(({ libraryName }) => {    return new RegExp(`("${libraryName}")|("${libraryName}")`).test(code);  });}
export interface Lib {  libraryName: string;  resolveStyle: (name: string) => string;}export type RegOptions =  | string  | RegExp  | Array<string | RegExp>  | null  | undefined;export interface VitePluginOptions {  include?: RegOptions;  exclude?: RegOptions;  libs: Lib[];}

換膚與暗黑風(fēng)格

換膚

在我們的less樣式中,會(huì)定義一系列如下的顏色梯度變量,其值由color-palette函數(shù)完成:

@blue-6: #3491fa;@blue-1: color-palette(@blue-6, 1);@blue-2: color-palette(@blue-6, 2);@blue-3: color-palette(@blue-6, 3);@blue-4: color-palette(@blue-6, 4);@blue-5: color-palette(@blue-6, 5);@blue-7: color-palette(@blue-6, 7);@blue-8: color-palette(@blue-6, 8);@blue-9: color-palette(@blue-6, 9);@blue-10: color-palette(@blue-6, 10);

基于此,我們?cè)傺莼鼍唧w場(chǎng)景下的顏色梯度變量:

@primary-1: @blue-1;@primary-2: @blue-2;@primary-3: @blue-3;// 以此類推...@success-1: @green-1;@success-2: @green-2;@success-3: @green-3;// 以此類推.../* @warn @danger @info等等 */

有了具體場(chǎng)景下的顏色梯度變量,我們就可以設(shè)計(jì)變量供給組件消費(fèi)了:

@color-primary-1: @primary-1;@color-primary-2: @primary-2;@color-primary-3: @primary-3;/* ... */
.argo-btn.arco-btn-primary {  color: #fff;    background-color: @color-primary-1;}

在使用組件庫的項(xiàng)目中我們通過 Less 的 ·modifyVars功能修改變量值:

Webpack配置

// webpack.config.jsmodule.exports = {  rules: [{    test: /.less$/,    use: [{      loader: "style-loader",    }, {      loader: "css-loader",    }, {      loader: "less-loader",     options: {       lessOptions: {         modifyVars: {           "primary-6": "#f85959",         },         javascriptEnabled: true,       },     },    }],  }],}

vite配置

// vite.config.jsexport default {  css: {   preprocessorOptions: {     less: {       modifyVars: {         "primary-6": "#f85959",       },       javascriptEnabled: true,     }   }  },}

設(shè)計(jì)暗黑風(fēng)格

首先,顏色梯度變量需要增加暗黑風(fēng)格。也是基于@blue-6計(jì)算,只不過這里換成了dark-color-palette函數(shù):

@dark-blue-1: dark-color-palette(@blue-6, 1);@dark-blue-2: dark-color-palette(@blue-6, 2);@dark-blue-3: dark-color-palette(@blue-6, 3);@dark-blue-4: dark-color-palette(@blue-6, 4);@dark-blue-5: dark-color-palette(@blue-6, 5);@dark-blue-6: dark-color-palette(@blue-6, 6);@dark-blue-7: dark-color-palette(@blue-6, 7);@dark-blue-8: dark-color-palette(@blue-6, 8);@dark-blue-9: dark-color-palette(@blue-6, 9);@dark-blue-10: dark-color-palette(@blue-6, 10);

然后,在相應(yīng)節(jié)點(diǎn)下掛載css變量

body {  --color-bg: #fff;    --color-text: #000;    --primary-6: @primary-6; }body[argo-theme="dark"] {  --color-bg: #000;    --color-text: #fff;    --primary-6: @dark-primary-6; }

緊接著,組件消費(fèi)的less變量更改為css變量:

.argo-btn.argo-btn-primary {  color: #fff;    background-color: var(--primary-6);}

此外,我們還設(shè)置了--color-bg,--color-text等用于設(shè)置body色調(diào):

body {  color: var(--color-bg);    background-color: var(--color-text);}

最后,在消費(fèi)組件庫的項(xiàng)目中,通過編輯body的argo-theme屬性即可切換亮暗模式:

// 設(shè)置為暗黑模式document.body.setAttribute("argo-theme", "dark")// 恢復(fù)亮色模式document.body.removeAttribute("argo-theme");

在線動(dòng)態(tài)換膚

前面介紹的是在項(xiàng)目打包時(shí)通過less配置修改less變量值達(dá)到換膚效果,有了css變量,我們可以實(shí)現(xiàn)在線動(dòng)態(tài)換膚。默認(rèn)的,打包過后樣式如下:

body {  --primary-6: "#3491fa"}.argo-btn {    color: #fff;    background-color: var(--primary-6);}

在用戶選擇相應(yīng)顏色后,我們只需要更改css變量--primary-6的值即可:

// 可計(jì)算selectedColor的10個(gè)顏色梯度值列表,并逐一替換document.body.style.setProperty("--primary-6", colorPalette(selectedColor, 6));// ....

文檔站點(diǎn)

還記得每個(gè)組件目錄下的TEMPLATE.md文件嗎?

## zh-CN```yamlmeta:  type: 組件  category: 通用title: 按鈕 Buttondescription: 按鈕是一種命令組件,可發(fā)起一個(gè)即時(shí)操作。```---## en-US```yamlmeta:  type: Component  category: Commontitle: Buttondescription: Button is a command component that can initiate an instant operation.```---@import ./__demo__/basic.md@import ./__demo__/disabled.md## API%%API(button.vue)%%## TS%%TS(interface.ts)%%

它是如何一步步被渲染出我們想要的界面呢?

TEMPLATE.md的作用

TEMPLATE.md將被解析并生成中英文版READE.md(組件使用文檔),之后在vue-router中被加載使用。

這時(shí)當(dāng)我們?cè)L問路由/button,vite服務(wù)器將接管并調(diào)用一系列插件解析成瀏覽器識(shí)別的代碼,最后由瀏覽器渲染出我們的文檔界面。

1. 解析TEMPLATE 生成 README

簡(jiǎn)單起見,我們忽略國(guó)際化和使用例子部分。

%%API(button.vue)%%%%INTERFACE(interface.ts)%%

其中button.vue就是我們的組件,interface.ts就是定義組件的一些接口,比如ButtonProps,ButtonType等。

解析button.vue

大致流程如下:

讀取TEMPLATE.md,正則匹配出button.vue;

使用vue-doc-api解析vue文件; let componentDocJson = VueDocApi.parse(path.resolve(__dirname, "button.vue"));

componentDocJson轉(zhuǎn)換成md字符串,md字符串替換掉占位符%%API(button.vue)%%,寫入README.md;

關(guān)于vue文件與解析出來的conponentDocJson結(jié)構(gòu)見 vue-docgen-api

解析interface.ts

由于VueDocApi.parse無法直接解析.ts文件,因此借助ts-morph解析ts文件并轉(zhuǎn)換成componentDocJson結(jié)構(gòu)的JSON對(duì)象,再將componentDocJson轉(zhuǎn)換成md字符串,替換掉占位符后最終寫入README.md;

讀取TEMPLATE.md,正則匹配出interface.ts;

使用ts-morph解析inerface.ts出interfaces;

interfaces轉(zhuǎn)componentDocJson;

componentDocJson轉(zhuǎn)換成md字符串,md字符串替換掉占位符%%API(button.vue)%%,寫入README.md;

import { Project } from "ts-morph";const project = new Project();project.addSourceFileAtPath(filepath);const sourceFile = project.getSourceFile(filepath);const interfaces = sourceFile.getInterfaces();const componentDocList = [];interfaces.forEach((interfaceDeclaration) => {  const properties = interfaceDeclaration.getProperties();  const componentDocJson = {    displayName: interfaceDeclaration.getName(),    exportName: interfaceDeclaration.getName(),    props: formatterProps(properties),    tags: {}  };  if (componentDocJson.props.length) {    componentDocList.push(componentDocJson);  }});// genMd(componentDocList);

最終生成README.zh-CN.md如下

```yamlmeta:  type: 組件  category: 通用title: 按鈕 Buttondescription: 按鈕是一種命令組件,可發(fā)起一個(gè)即時(shí)操作。```@import ./__demo__/basic.md@import ./__demo__/disabled.md## API### `<button>` Props|參數(shù)名|描述|類型|默認(rèn)值||---|---|---|:---:||type|按鈕的類型,分為五種:次要按鈕、主要按鈕、虛框按鈕、線性按鈕、文字按鈕。|`"secondary" | "primary" | "dashed" | "outline" | "text"`|`"secondary"`||shape|按鈕的形狀|`"square" | "round" | "circle"`|`"square"`||status|按鈕的狀態(tài)|`"normal" | "warning" | "success" | "danger"`|`"normal"`||size|按鈕的尺寸|`"mini" | "small" | "medium" | "large"`|`"medium"`||long|按鈕的寬度是否隨容器自適應(yīng)。|`boolean`|`false`||loading|按鈕是否為加載中狀態(tài)|`boolean`|`false`||disabled|按鈕是否禁用|`boolean`|`false`||html-type|設(shè)置 `button` 的原生 `type` 屬性,可選值參考 [HTML標(biāo)準(zhǔn)](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type "_blank")|`"button" | "submit" | "reset"`|`"button"`||href|設(shè)置跳轉(zhuǎn)鏈接。設(shè)置此屬性時(shí),按鈕渲染為a標(biāo)簽。|`string`|`-`|### `<button>` Events|事件名|描述|參數(shù)||---|---|---||click|點(diǎn)擊按鈕時(shí)觸發(fā)|event: `Event`|### `<button>` Slots|插槽名|描述|參數(shù)||---|:---:|---||icon|圖標(biāo)|-|### `<button-group>` Props|參數(shù)名|描述|類型|默認(rèn)值||---|---|---|:---:||disabled|是否禁用|`boolean`|`false`|## INTERFACE### ButtonProps|參數(shù)名|描述|類型|默認(rèn)值||---|---|---|:---:||type|按鈕類型|`ButtonTypes`|`-`|

2. 路由配置

const Button = () => import("@argo-design/argo-ui/components/button/README.zh-CN.md");const router = createRouter({  {    path: "/button",  component: Button  }});export default router;

3. README是如何被渲染成UI的

首先我們來看下README.md(為方便直接省略.zh-CN)以及其中的demos.md的樣子與它們最終的UI。

可以看到,README就是一系列demo的集合,而每個(gè)demo都會(huì)被渲染成一個(gè)由代碼示例與代碼示例運(yùn)行結(jié)果組成的代碼塊。

開發(fā)vite-plugin-vue-docs解析md

yarn create vite快速搭建一個(gè)package

// vite.config.tsimport { defineConfig } from "vite";import vue from "@vitejs/plugin-vue";import md from "./plugins/vite-plugin-md/index";export default defineConfig({  server: {    port: 8002,  },  plugins: [md(), vue()],});
// App.vue<template>  <ReadMe /></template><script setup>import ReadMe from "./readme.md";</script>
// readme.md@import ./__demo__/basic.md

開發(fā)之前我們先看看插件對(duì)README.md源碼的解析轉(zhuǎn)換流程。

1. 源碼轉(zhuǎn)換

首先我們來實(shí)現(xiàn)第一步: 源碼轉(zhuǎn)換。即將

@import "./__demo__/basic.md"

轉(zhuǎn)換成

<template>  <basic-demo /></template><script>import { defineComponent } from "vue";import BasicDemo from "./__demo__/basic.md";export default defineComponent({  name: "ArgoMain",  components: { BasicDemo },});</script>

轉(zhuǎn)換過程我們借助第三方markdown解析工具marked完成,一個(gè)高速,輕量,無阻塞,多平臺(tái)的markdown解析器。

眾所周知,md2html規(guī)范中,文本默認(rèn)會(huì)被解析渲染成p標(biāo)簽。也就是說,README.md里的@import ./__demo__/basic.md會(huì)被解析渲染成<p>@import ./__demo__/basic.md</p>,這不是我想要的。所以需要對(duì)marked進(jìn)行一下小小的擴(kuò)展。

// marked.tsimport { marked } from "marked";import path from "path";const mdImport = {  name: "mdImport",  level: "block",  tokenizer(src: string) {    const rule = /^@import\s+(.+)(?:\n|$)/;    const match = rule.exec(src);    if (match) {      const filename = match[1].trim();      const basename = path.basename(filename, ".md");      return {        type: "mdImport",        raw: match[0],        filename,        basename,      };    }    return undefined;  },  renderer(token: any) {    return `<demo-${token.basename} />\n`;  },};marked.use({  extensions: [mdImport],});export default marked;

我們新建了一個(gè)mdImport的擴(kuò)展,用來自定義解析我們的md。在tokenizer 中我們定義了解析規(guī)則并返回一系列自定義的tokens,其中raw就是@import "./__demo__/basic.md",filename就是./__demo__/basic.md,basename就是basic,我們可以通過marked.lexer(code)拿到這些tokens。在renderer中我們自定義了渲染的html,通過marked.parser(tokens)可以拿到html字符串了。因此,我們開始在插件中完成第一步。

// index.tsimport { Plugin } from "vite";import marked from "./marked";export default function vueMdPlugin(): Plugin {  return {    name: "vite:argo-vue-docs",    async transform(code: string, id: string) {      if (!id.endsWith(".md")) {        return null;      }      const tokens = marked.lexer(code);      const html = marked.parser(tokens);      const vueCode = transformMain({ html, tokens });    },  };}
// vue-template.tsimport changeCase from "change-case";import marked from "./marked";export const transformMain = ({  html,  tokens,}: {  html: string;  tokens: any[];}): string => {  const imports = [];  const components = [];  for (const token of tokens) {    const componentName = changeCase.pascalCase(`demo-${token.basename}`);    imports.push(`import ${componentName} from "${token.filename}";`);    components.push(componentName);  }  return `  <template>    ${html}  </template>  <script>import { defineComponent } from "vue";${imports.join("\n")};export default defineComponent({  name: "ArgoMain",  components: { ${components.join(",")} },});</script>`;};

其中change-case是一個(gè)名稱格式轉(zhuǎn)換的工具,比如basic-demo轉(zhuǎn)BasicDemo等。

transformMain返回的vueCode就是我們的目標(biāo)vue模版了。但瀏覽器可不認(rèn)識(shí)vue模版語法,所以我們?nèi)砸獙⑵浣唤o官方插件@vitejs/plugin-vuetransform鉤子函數(shù)轉(zhuǎn)換一下。

import { getVueId } from "./utils";export default function vueMdPlugin(): Plugin {  let vuePlugin: Plugin | undefined;  return {    name: "vite:argo-vue-docs",    configResolved(resolvedConfig) {      vuePlugin = resolvedConfig.plugins.find((p) => p.name === "vite:vue");    },    async transform(code: string, id: string) {      if (!id.endsWith(".md")) {        return null;      }      if (!vuePlugin) {        return this.error("Not found plugin [vite:vue]");      }      const tokens = marked.lexer(code);      const html = marked.parser(tokens);      const vueCode = transformMain({ html, tokens });      return await vuePlugin.transform?.call(this, vueCode, getVueId(id));    },  };}
// utils.tsexport const getVueId = (id: string) => {  return id.replace(".md", ".vue");};

這里使用getVueId修改擴(kuò)展名為.vue是因?yàn)?code>vuePlugin.transform會(huì)對(duì)非vue文件進(jìn)行攔截就像我們上面攔截非md文件一樣。

configResolved鉤子函數(shù)中,形參resolvedConfig是vite最終使用的配置對(duì)象。在該鉤子中拿到其它插件并將其提供給其它鉤子使用,是vite插件開發(fā)中的一種“慣用伎倆”了。

2. 處理basic.md

在經(jīng)過vuePlugin.transform及后續(xù)處理過后,最終vite服務(wù)器對(duì)readme.md響應(yīng)給瀏覽器的內(nèi)容如下

對(duì)于basic.md?import響應(yīng)如下

可以看到,這一坨字符串可沒有有效的默認(rèn)導(dǎo)出語句。因此對(duì)于解析語句import DemoBasic from "/src/__demo__/basic.md?import";瀏覽器會(huì)報(bào)錯(cuò)

Uncaught SyntaxError: The requested module "/src/__demo__/basic.md?import" does not provide an export named "default" (at readme.vue:9:8)

在帶有module屬性的script標(biāo)簽中,每個(gè)import語句都會(huì)向vite服務(wù)器發(fā)起請(qǐng)求進(jìn)而繼續(xù)走到插件的transform鉤子之中。下面我們繼續(xù),對(duì)/src/__demo__/basic.md?import進(jìn)行攔截處理。

// index.tsasync transform(code: string, id: string) {  if (!id.endsWith(".md")) {    return null;  }  // 新增對(duì)demo文檔的解析分支  if (isDemoMarkdown(id)) {    const tokens = marked.lexer(code);    const vueCode = transformDemo({ tokens, filename: id });    return await vuePlugin.transform?.call(this, vueCode, getVueId(id));  } else {    const tokens = marked.lexer(code);    const html = marked.parser(tokens);    const vueCode = transformMain({ html, tokens });    return await vuePlugin.transform?.call(this, vueCode, getVueId(id));  }},
// utils.tsexport const isDemoMarkdown = (id: string) => {  return //__demo__//.test(id);};
// vue-template.tsexport const transformDemo = ({  tokens,  filename,}: {  tokens: any[];  filename: string;}) => {  const data = {    html: "",  };  const vueCodeTokens = tokens.filter(token => {    return token.type === "code" && token.lang === "vue"  });  data.html = marked.parser(vueCodeTokens);  return `  <template>    <hr />    ${data.html}  </template>  <script>import { defineComponent } from "vue";export default defineComponent({  name: "ArgoDemo",});</script>`;};

現(xiàn)在已經(jīng)可以在瀏覽器中看到結(jié)果了,水平線和示例代碼。

3. 虛擬模塊

那如何實(shí)現(xiàn)示例代碼的運(yùn)行結(jié)果呢?其實(shí)在對(duì)tokens遍歷(filter)的時(shí)候,我們是可以拿到vue模版字符串的,我們可以將其緩存起來,同時(shí)手動(dòng)構(gòu)造一個(gè)import請(qǐng)求import Result from "${virtualPath}";這個(gè)請(qǐng)求用于返回運(yùn)行結(jié)果。

export const transformDemo = ({  tokens,  filename,}: {  tokens: any[];  filename: string;}) => {  const data = {    html: "",  };  const virtualPath = `/@virtual${filename}`;  const vueCodeTokens = tokens.filter(token => {    const isValid = token.type === "code" && token.lang === "vue"    // 緩存vue模版代碼    isValid && createDescriptor(virtualPath, token.text);    return isValid;  });  data.html = marked.parser(vueCodeTokens);  return `  <template>    <Result />    <hr />    ${data.html}  </template>  <script>import { defineComponent } from "vue";import Result from "${virtualPath}";export default defineComponent({  name: "ArgoDemo",  components: {    Result  }});</script>`;};
// utils.tsexport const isVirtualModule = (id: string) => {  return //@virtual/.test(id);};
export default function docPlugin(): Plugin {  let vuePlugin: Plugin | undefined;  return {    name: "vite:plugin-doc",    resolveId(id) {      if (isVirtualModule(id)) {        return id;      }      return null;    },    load(id) {      // 遇到虛擬md模塊,直接返回緩存的內(nèi)容      if (isVirtualModule(id)) {        return getDescriptor(id);      }      return null;    },    async transform(code, id) {      if (!id.endsWith(".md")) {        return null;      }      if (isVirtualModule(id)) {        return await vuePlugin.transform?.call(this, code, getVueId(id));      }      // 省略其它代碼...    }  }}
// cache.tsconst cache = new Map();export const createDescriptor = (id: string, content: string) => {  cache.set(id, content);};export const getDescriptor = (id: string) => {  return cache.get(id);};

最后為示例代碼加上樣式。安裝prismjs

yarn add prismjs
// marked.tsimport Prism from "prismjs";import loadLanguages from "prismjs/components/index.js";const languages = ["shell", "js", "ts", "jsx", "tsx", "less", "diff"];loadLanguages(languages);marked.setOptions({  highlight(    code: string,    lang: string,    callback?: (error: any, code?: string) => void  ): string | void {    if (languages.includes(lang)) {      return Prism.highlight(code, Prism.languages[lang], lang);    }    return Prism.highlight(code, Prism.languages.html, "html");  },});

項(xiàng)目入口引入css

// main.tsimport "prismjs/themes/prism.css";

重啟預(yù)覽,以上就是vite-plugin-vue-docs的核心部分了。

遺留問題

最后回到上文構(gòu)建組件style/index.ts遺留的問題,index.ts的內(nèi)容很簡(jiǎn)單,即引入組件樣式。

import "../../style/index.less"; // 全局樣式import "./index.less"; // 組件樣式復(fù)制代碼

index.ts在經(jīng)過vite的lib模式構(gòu)建后,我們?cè)黾觕ss插件,在generateBundle鉤子中,我們可以對(duì)最終的bundle進(jìn)行新增,刪除或修改。通過調(diào)用插件上下文中emitFile方法,為我們額外生成用于引入css樣式的css.js。

import type { Plugin } from "vite";import { OutputChunk } from "rollup";export default function cssjsPlugin(): Plugin {  return {    name: "vite:cssjs",    async generateBundle(outputOptions, bundle) {      for (const filename of Object.keys(bundle)) {        const chunk = bundle[filename] as OutputChunk;        this.emitFile({          type: "asset",          fileName: filename.replace("index.js", "css.js"),          source: chunk.code.replace(/.less/g, ".css")        });      }    }  };}

結(jié)語

下篇暫定介紹版本發(fā)布,部署站點(diǎn),集成到在線編輯器,架構(gòu)復(fù)用等,技術(shù)涉及l(fā)inux云服務(wù)器,站點(diǎn)服務(wù)器nginx,docker,stackblitz等。

(學(xué)習(xí)視頻分享:vuejs入門教程、編程基礎(chǔ)視頻)

以上就是【由淺入深】vue組件庫實(shí)戰(zhàn)開發(fā)總結(jié)分享的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!

關(guān)鍵詞: Vue.js Vite

一级黄色片录像片| 日本一道本美女久久| 免费一区二区风骚徐娘| 国产免费精品久久久| 出轨少妇自白小说| 国产美女蜜臀av怡红| 久久久久久精品国产婷婷| 老司机中文视频网| 国产精品久久国产丁香花| 人人妻人人澡人人爽人人a v| 天天操天天爽天天舔天天射| 国产91品久久久久久久久| 国产精品久久久久久av福利| 色婷婷美国农夫综合激情亚洲| 日韩一区不卡二区| 国产av激情国产熟女| 日韩午夜激情av| 免费观看视频成人| 亚洲成网在线观看| 国产av专区网站大全| 日韩美女中文字幕在线看| 1024日韩精品一区二区| 91碰碰成人免费视频| 午夜精品在线观看成人| 97色伦午夜国产亚洲精品| 国产第一影院草草影院久久| 日韩人妻系列超碰无码| 国产日韩高清一区二区| 国产精品很黄很色很爽的网站| 国产 精品 9999| 日韩成人免费电影一区二区三区 | 国产精品一区二区三区色 | 91人妻久久久精品中文字幕| 91久久国语露脸精品国产| 九色原创自拍视频| 26uuu日韩一区二区三区四区| 国产一区激情视频在线播放| 天天插天天日天天啪| 国产伦精一区二区三区| 97香蕉碰碰人人澡人人爱| 美女黄页网站久久久久久| 天天日天天插天天操天天射天天喷| 日韩永久免费av网站| 国产一区二区三区自拍欧美| 成人伊人精品色xxxx视频| 亚洲av永久天码精品天堂dl| 少妇被爽到高潮喷水久久| 91精品久久久久含羞草| 亚洲男人一区二区三区| 亚洲 校园 春色 另类 激情| 久久久久久久日本综合| 国产av高清无限看| 国产女同一区二区久久| 国产黄色一级黄色大片| 97香蕉碰碰人人澡人人爱| 亚洲人妻自拍偷拍| 九九re热国产精品视频| 男人操女人中国产视频| 一区二区三区精品精品| 久久精品国产亚洲激激情| 国产精品欧美日韩在线观看一区| 草原免费视频亚洲| 国产精品久久久久久入口| 国产在线av小视频| 久久久久久久久波多野高潮| 1024在线国产视频| 亚洲五月婷婷啪啪| rct378在线中文字幕| 亚洲av综合av一区二区综| 欧美黄色性感网站| 欧美日韩国产激情不卡| 色香蕉av一区二区| 人妻 制服 日韩 中文 在线| 中文字幕人妻少妇一区二区| 日本少妇色诱视频| 九九久久精品免费看| 国产精品igao激情| 亚洲成人影院麻豆| 久久久久久久久久久久久福利| 91精品国产麻豆自产在线| 国产美女一区二区三区五区| 伊人av在线播放| 国产成人h片在线观看| 超碰人妻人人爱人人干| 欧美一区二区三区四区在线| 亚洲久久9999| 久久精品久久久久久久久久| 日韩精品中文字幕资源| 亚洲国产长腿丝袜av天堂| 午夜免费一区二区三区精品福利 | 亚洲欧美日韩激情视频| 亚洲天堂国产精品区| 日本中文字幕在线观看免费 | 亚洲最大综合久久网成人| 午夜一区二区三区视频不卡| 午夜免费观看国产视频| 少妇人妻一区二区网站| 调教女m在线观看| 国产熟妇另类久久久久久| 蜜桃福利视频一区二区| 人妻干亚洲一区中文字幕| 亚洲熟女av观看| 亚洲熟女少妇一区二区三区在线| 日本亚洲欧洲色a| 久久久无码国产精品古装| 人妻 制服 日韩 中文 在线| 一区二区三区亚洲社区| 中国精品久久久久久| 国产日韩欧美三级在线| 亚洲成在人线视av| 亚洲一区成人动漫在线观看| 少妇被爽到高潮喷水久久夜色| 神马伊人网久久久久久久久久久| 超碰97免费公开在线人妻| 国内偷拍视频免费久久| 我要看黄色一级影视片| 色婷婷亚洲午夜激情| 亚洲精品乱码久久久久蜜桃网站| 少妇高潮久久久久丙内射| 人妻少妇精品视频一区97| 午夜影院成人av| 三级久久国产试看3分钟| 国产一区二区三区女人的床叫声| 亚洲欧美精品卡一卡二卡三| 深夜激情小视频在线观看| 人妻素人中出一区二区三区| 99久国产精品午夜性色福利| 国产av高潮大全| 亚洲最大综合久久网成人| 婷婷丁香亚洲五月天| 国产一区二区在线激情欧美| 久久国产精品免费看三级| 中文字幕 日韩 麻豆| 国产亚洲欧美日韩国产精品三区| 日韩av网站 狠狠| 色就是色综合欧美色| 国产熟女一区二区91| 91精品爽啪在线观看| 欧美国产日本精品| 亚洲自治区二色一区二区三区| 美女扒开逼逼让男人操| 亚洲欧美熟女一区二区三区| 那个小区的人妻在线观看| 在线视频青青青草| 国产夫妻自拍啪啪视频| 亚洲精选国产一区| 亚洲精品免费天堂| 制服丝袜美腿一区二区在线观看| 偷拍亚洲另类av| 97视频都是精品| 国产精品久久久久久久久av| 超碰人人97青青草| 无人一区二区三区在线观看视频| 亚洲区欧美区自拍偷拍区| 一级特色特级黄大片| 久久久蜜桃成人网| 99热精品在线免费观看| 人妻少妇精品在线视频| 一色桃子av人妻中文字幕| 国产99精品久久久久久久| 99视频这里都是精品6| av影音在线不卡| 日韩 午夜 免费| 伊人久久视频在线播放| 日一区二区三区在线视频| 亚洲国产日韩欧美精品综合| 在线 亚洲 精品| 不卡av中文字幕手机看| 国内偷拍视频久久久久久| 青青草国产在线免费观看| av天堂中文字幕尤物| 2025av熟女| 日本大香蕉怡红院| 在线另类播放蜜桃| 久久久精品国产人妻在线观看| 91亚洲人妻一区二区三区| 激情懂色av一区av二区av| 999爱在线观看视频| 成人av欧美在线观看| 美女小视频在线观看| 亚洲一区二区三区四区在线网站| 日韩免费三级视频| 亚洲国产天堂在线| 熟妇 人妻 中文| 2020国内自拍视频| 日韩成人午夜福利影院| 日本免费久久精品| 精品国偷自产一区二区三区免费| 中文字幕亚洲素人| 婷婷激情中文字幕组| 强伦人妻一区二区三区视频18| 玩弄超骚少妇一区二区三区 | 成人午夜毛片在线| 成人午夜福利视频免费看| 日韩av网站 狠狠| 青青草久久久久久久久久| 国产精品高清在线观看| 人人妻人人爱人人澡| 狠狠操狠狠干狠狠操狠狠干| 日韩美女中文字幕在线看| 九九精品在线观看视频| 久久久久久精品免费免费sss| 中文字幕乱码一区久久| 欧美 日韩亚洲一区| 欧美日韩成人在线高清| 97特黄一级中文字幕在线| 日韩精品在线午夜| 黄色一级片人和狗| 日韩三级电影一区二区三区| 亚洲天堂国产精品区| 中文一区二区人妻| 蜜臀久久午夜小视频,| 日韩高清av在线免费观看| 国内精品伊人久久久久av网站| 精品黄色美女一二区| 7au.cn成人午夜在线| 国产 日韩 精品在线观看| 97久久香蕉国产线看观看| 蜜臀精品人妻社区一区| 久久视频这里只精品| 大桥久未无码吹潮在线观看| 99在这里只有精品2| 亚洲一区两区三区四区| 美女扒开逼逼让男人操| 日韩一区二区三区四区不卡网| 久久伊人中文字幕有码| yy8098国产av久久| 欧美精产国品一二三www| 91精品人妻呻吟| 999精品视频在线免费九九看| 亚洲中文字幕在线视频播放| 国产裸体学生视频全黄网站| 日韩亚洲在线成人| 国产99精品久久久久久久| 欧美日韩亚洲成人一区| 日韩欧美亚洲精品人妻| 午夜天堂久久电影| 日韩三级电影一区二区三区| 一区二区三区精品精品| 国产精品久久久久久久久av| 亚州av男人天堂| 97视频都是精品| 久久综合另类激情人妖| 99在这里只有精品2| 亚洲 欧美 中文字幕第一页| 日韩色图欧美视频| 91在线在线免费视频| 精精品人妻一区二区| 97综合精品视频| 鸡巴插洞穴的软件免费试看| 91性高久久久久久久久| 久久国产精品波多野吉衣av| 欧美日韩少妇熟女| 久久少妇高潮视频免费| 91色综合综合热五月激情| 日本伊人网在线播放| 日韩av在线大片| 一本色道久久亚洲精品网| 国产卡一卡二专区| 狠狠挺进h嗯啊第一次视频| 一区二区三区四区av| 日韩国产欧美激情在线视频| 国产99丝袜诱惑| 国产黄色剧情影片麻豆免费播放 | 日韩av永久免费观看| 成人动漫av一区二区| 偷拍视频你懂的一区二区三区| 亚洲蜜桃臀av在线| 中文在线字幕丝袜美腿| 亚洲五区四区三区二区| 一区二区久久在线观看| 无套内射处女在线观看| 久久久久久精品成人| 日韩美女中文字幕在线看| 国产婷婷精品av在线| 日本伦理在线不卡| 日韩国产成人一区| 五月大香蕉综合婷婷| 熟妇人妻中出视频| 日韩一二三区视频免费观看| 巨乳中文字幕一区| 日韩免费av在线观看激情| 一区二区精品视频乱码| 日韩蜜臀人妻素人精品在线观看 | 亚洲av少妇高潮150p| 肥屁股高潮迭起一区二区的视频| 国产强上美女在线观看| 青青操在观看视频| 欧洲美女福利一区二区三区| 欧美熟妇大阴蒂高潮系列| 最新国产激情视频| 大龄岳母的诱惑电影在线观看| 日韩美女少妇av| 亚洲色影在线视频| av伊人网在线播放| 天天操天天透天天射| 久久久久久久久波多野高潮| 欧美乱视频一区二区三区| 五月婷中文字幕网| 色综合久综合久久综合久鬼88 | 色在线观看aaa| 日韩深喉口爆吞精| 日本伦理视频在线| 青青草原国产在线精品| 久久免费又粗又长又硬又深又色| 熟妇人妻中出视频| 久久国产成人精品免费视频| 亚洲av乱码一区二区三区蜜臀| 日本道久久综合久久| 黄色一级片人和狗| 国产av 一区二区三区| 中文字幕一区在线精品| 国产精品久久久久久av大片| 91学生片黄在线网站| 美女网站视频大全| 午夜精品一区二区三区蜜桃| 蜜桃成人永久免费av大| 丁香欧美欧美欧美欧美欧美| 亚洲精品自拍产在线观看 | 国产熟女啪啪精品一区二区三区| 99热这里只有精品在线| 国产成人AV无码一二三区| 中文字幕亚洲综合色| 亚洲欧美日韩综合在线丁香| 99手机视频免费在线观看| 一区二区三区四区丝袜 | 久久久蜜桃精品人妻一区| 国产一级激情黄色av| 亚洲av日韩精品久久国产多毛女| 亚洲男人av天堂精| 国产精品久久国产丁香花| 免费黄色特级大片| 亚洲黄色尻逼网站| 九九热九九色九九操| 日本高清中文字幕久久| 自拍另类亚洲欧美| 99热这里有国产| 91捷克街头在线播放| 中文字幕无线码在线观看| 青青草欧美激情在线视频| 久久精品视频天天操| 91国产老熟女精品| 欧美一区二区高清视频在线观看| 婷婷深爱激情四射| 青青草原国产在线精品| 久久亚洲欧美日本精品品| 成人中文字幕专区| 欧美精品久久久久三级| 91熟女国产老熟女| 亚洲中文国产字幕| 大香网伊人久久综合网20| 久久成年人免费网站| 搜索人妻av中文字幕| 在线另类播放蜜桃| 黑人一区二区三区四区五区| 亚洲国产久一区二区三区| 99久久成人精品国产网站| 国产亚洲精品久久久久久女人| 超碰caoporn免费| 谁有av网站在线播放中文字幕| 国产 欧美?亚洲?日韩视频| 日韩无码电影一区二区三区四区| 国产视频1区二区三区| 色狠狠亚洲爱综合国产| 麻豆精品少妇在线视频| 黑人上司魅惑人妻电影| 在线中文字幕国产精品| 一区二区三区精品精品| 经典a级片在线观看| 日韩人妻中文字幕视频| 无人区午夜精品乱码一区二区| 999欧美一区二区三区| 国产精品熟女高潮久久99| 青青草原国产在线精品| 黄色午夜免费网站| 亚洲啊v男人天堂| 熟女av高清一区二区三区| 熟女人妻在线视频第一页| 久久精品国产亚洲激激情| 一区二区久久在线观看| 日韩中文字幕一区二区高清| 在线 亚洲 精品| 中文字幕av久久爽伊人一级| 日韩精品少妇熟女| 天天色天天干天天| 精品久久久久久久久字幕| 中文字幕av三级免费| 久久99 国产精品| 久久成人av一区二区| 国产av 在线视频| 国产91在线播放网址| 在线观看视频瑟瑟| 亚洲 成人 av 在线| 日韩永久免费av网站| 2019年中文字幕在线| 亚洲国产精品成人久久久| 天天色天天色天天操| 中文有码字幕在线| 52av成人久久国产一区| 人人妻人人爱人人澡| 高清在线 中文字幕| 欧美精品一区二区免费开放| 91学生片黄在线网站| 国产成人午夜电影在线观看免费| 开心网五月天色婷婷| av爱爱亚洲一区| 99日韩欧美在线观看| 久久国产精品亚洲欧美阿娇| 清纯唯美亚洲五月激情综合| 欧美视频观看99| 欧美国产日韩成人一区二区三区| 在线观看视频瑟瑟| 国产精品一级999| 91精品人妻麻豆| 亚洲精品自拍产在线观看| 日韩毛片免费播放| 骚逼被大鸡吧插视频| 午夜天堂久久电影| 国产精品久久久久久av蜜臀| 国产精品久久久久久人妻爽| 亚洲成网在线观看| 亚洲丝袜美女诱惑| 美国av韩国av国产av| 亚洲中文av天堂| www.亚洲综合色| 亚洲一区在线蜜桃| 婷婷激情网婷婷激情网| 日韩av网站 狠狠| 青青爽视频免费在线观看| 和大屁股女人臀交| 人妻中文字幕精品| 国内精品久久久久久精品视频| 成人午夜毛片在线| 精品999国内一二三区| 偷拍av高清资源| 欧美日韩av一区=区三区| 久久精品国产亚洲激激情| 亚洲天堂日韩美女| 婷婷综合在线五月天| 黄色理论片在线观看| 免费黄色特级大片| 91精品成人在线视频| 亚洲av 亚州人妻中文字幕| 国产av一区二区三区亚洲人妻| 久久久综合网久久久综合网| 国产中文字幕在线第一页| 免费黄页网址大全在线观看| 高清视频区二区三区| 啄木乌av一区二区三区| 六十路丰乳老熟女| 国产一区二区在线播| 丝袜人妻精品一区二区三区| 和熟女打炮国产视频| 黄色理论片在线观看| 久久久久久国产精品av| 中文字幕中文字幕中文字幕| 色综合久久综合久久综合网| 暖暖视频高清在线观看中文| 中文人妻一区二区视频| 99只有精品在线观看| 久久久久亚洲国产av| 国产精品18久久久| 大香蕉伊人免久久| 亚洲一卡2卡三卡| 日韩av俩男操女人吃奶| 中文人妻熟妇精品乱又伧不卡| 蜜臀 av 一区二区| av人妻精品一区二区三区| www 超碰97在线观看com| 中文字幕在线三级| 天天天操天天干天天日| 国产精品欧美一区二区三区不卡| 99久久九九社区精品| 18禁涩涩网站在线| 日本男人操日本女人视频| 久久91精品国产91久久蜜月 | 国产成人在线免费视频| 色狠狠亚洲爱综合国产| 九九在线观看视频国产剧情| 96国产av传媒精品| 1024人妻熟女一区二区三区| 日韩免费av在线观看激情| 日韩色图欧美视频| 免费看的日本一级片| 亚洲最大黄色福利| 国产精品久久久久精品三级a| 中文字幕av人妻呻吟| 一本大道久久a久久综合精品| 熟妇在线精品视频网站| 91欧美日韩在线观看视频| 亚洲av超清在线| 操操操操夜夜夜夜| 那个小区的人妻在线观看| 麻豆影视精品在线观看| 色婷婷五月亚洲综合小说| 亚洲精品性色av| www.狠狠视频.com| 免费97人妻一区二区三区| 亚洲天堂国产精品区| 91人妻人人澡人人爽人人精品6| 国av一区二区三区| 日本爱片在线观看| 日韩精品少妇熟女| 久久久久久亚洲精品不卡| 欧美视频亚洲视频在线观看| 麻豆精品国产传媒美女网站| 手机在线日韩av| 成人短视频在线版| 麻豆成人性电影在线观看视频| 日本高清中文字幕久久| 19国产精品麻豆| 国产剧情福利在线播放| av网站软件在线播放| 人人妻人人澡人人爽人人精品直播| 无套内射处女在线观看 | 亚洲欧美国产免费| a在线视频播放免费网站| 日韩精品欧美嫩草久久99| 午夜精品一区二区三区蜜桃| 色吧中文字幕在线| 伊人久久大香线蕉综合啪小说| 亚洲国产欧美另类| 99久精品综合在线观看| 久久日韩精品中文字幕人妻熟女| 四虎影院一级黄色片| 欧美一区三区三区高中清不卡 | 美女穿丝袜美腿热吻男人| 久久国产成人精品a| av影音在线不卡| 丝袜美腿诱惑福利| 亚洲精品又黄又爽的视频| 日韩成人午夜福利影院| 人妻av中文字幕网| 久久精品国产精品国产精品国产| 精品麻豆久久久久久| yy8098国产av久久| 高清有码中文字幕在线观看| 蜜月久综合久久综合国产| 免费观看日韩一级黄色大片 | 亚洲av男人的天堂久久精品| 黄色午夜免费网站| 国产第一影院草草影院久久| 国产亚洲精品久久久久久女人| 草原免费视频亚洲| 婷婷六月亚洲综合| www国产精品人妻一二三区| 国产91精品福利在线观看| 天天综合天天精品| 免费观看日韩一级黄色大片| 91高清视频在线一区| 欧美情色免费视频| 久久久久久久久久久东京| 国产伦理精品av| 蜜桃av在线观看一区| 7890大逼操鸡巴| 国产夫妻自拍啪啪视频| 中文字幕久久中文字幕综合网| 偷拍自拍亚洲专区| 4438x亚洲最大成人网| 亚洲精品91av在线| 淫妇操BBB操BBB操BBB| 91青青草这里只有精品| 97色在线电影免费观看| 亚洲99福利视频| 日韩中文字幕在线第一页| 日韩精品中文字幕巨臀人妻中出| 欧美日韩三级在线综合| 日韩超碰97在线观看| 亚洲一区天堂在线| 国产 欧美?亚洲?日韩视频| 视色视频成人午夜精品| 久久久久久国产精品av| 婷婷只有在线精品视频| 国产人妻av在线看| 日韩中文字幕第十页| 精品亚洲午夜久久久久四季| 人妻熟女中文av| 欧美男女啪啪真人视频| 国产精品黑丝美腿美臀| 天天天天天天天天天天天天天天干| 亚洲精品在线观看av密乳av| 国产av久久久久久久| 黄色午夜免费网站| 超碰97免费公开在线人妻| 久久久久久久久久免费观看视频 | 91 亚洲 在线| 成人美女在线视频| 国产老熟露脸对白| 亚洲天堂黄色网络| 国产亚洲精品久久久一区二区| 日韩人妻系列超碰无码| 午夜一级免费福利视频| 青青草国产在线免费观看| 人妻丰满精品一区二区A片| 色综合久久综合久久综合网| 午夜一区二区三区视频不卡| 亚洲国产一区91| 激情五月婷婷婷婷婷婷婷| 久久精品久久久久久久久久| 久久国语露脸精品国产麻豆| 日本伦理视频在线| 亚洲性感天堂欧美| 国产免费精品在线播放| 91国语对白精品露脸| 久久日韩美女人妻精品| 2025av熟女| 亚洲一区两区三区四区| 麻豆精选在线播放视频| 日本影片高清视频| 美女扒开逼逼让男人操| 国产69精品久久久/| 国产精品免费自拍视频大全| 网页端在线聊天室| 久久ye九九视频免费观看| 最新国产精品手机网站| 成人午夜毛片在线| 国产欧美在线亚洲| 91久久美女高潮喷水| 久久精品av网站在线播放| 国产欧美日韩成人一区二区| 青青青操国产在线视频| 欧美熟妇大阴蒂高潮系列| 伊人久久大香线蕉av色婷婷色| 在线观看欧美激情| 日韩一二三区视频免费观看| 激情欧美一区二区三区| 亚洲在线一区二区在线观看| 99偷拍精品一区二区| 久久亚洲欧美日本精品品| 亚洲av狠狠做五月| 国产69精品久久久久乱码| 加勒比东京热综合888| 人人妻人人]人人澡欧美一区| 精品人妻日日夜夜操| 亚洲最大熟妇人妻| 变态另类天堂在线播放| 久久国语露脸精品国产麻豆| 伊人网在线播放av电影| 欧美日韩国产最新久久| 国产精品吴梦梦视频| 少妇精品久久综合网| 激情五月婷婷婷婷婷婷婷| 91国产精品久久久久| 亚洲天堂成人网入口| 日韩欧美一区黄色| 开心网五月天色婷婷| 国产黄色一级黄色大片| 三级日本在线观看网站| 91在线在线免费视频| 国产精品综合久久桃花| 99在线午夜日韩视频| 成人免费av专区| 久久 91 欧美 精品| 国产亚洲精品av成人无删减| 日本久久久久久久国产精品| 疯狂人妻丝袜系列| 亚洲丝袜美女诱惑| 午夜8050网站二级| 亚洲区欧美区自拍偷拍区| 欧美国产日本精品| 国产一级激情黄色av| 热久久77这里有精品综合久久| av一区二区三区久久久| 91极速版免费视频| 九色视频蝌蚪在线免费观看| 日韩中文字幕综合在线网| 精品中文字幕久久久久久| 97久久久超国产精品05后| 久久午夜国产精品| 亚洲一区二区三区四区在线网站| 国产视频欧美一区二区| 国产乱码一区二区三区四区| 黄色一级成人大片| 久久久人妻视频免费观看| 欧美激情亚洲激情亚洲| 午夜精品久久久内射| 青青草免费国产视频| 婷婷在线www.| 亚洲狠狠插2020| 77777蜜臀精品久久综合| 丁香花中文字幕在线观看| 国产懂色av熟女丝袜精品| 国产婷婷精品av在线| av影音在线不卡| 青青草原vip在线视频| 国产黄色剧情影片麻豆免费播放| 一区二区三区亚洲社区| 国产熟女啪啪精品一区二区三区 | 人妻丰满熟妇av一区二区| 日韩欧美一卡二卡在线观看视频| 玖玖在线视频精品| 97狠狠狠狠狠狠狠| 日韩 午夜 免费| 国产精品色婷婷久久58| 日韩啊v视频在线| 精彩av在线不卡播放| 亚洲av黄久久久| 加勒比东京热综合888| 婷婷亚洲综合久久| 亚洲av色图网站| 麻豆精品少妇在线视频| 蜜桃福利视频一区二区| 麻豆国产在线观看视频| 欧美无吗一区二区三区| 午夜18在线观看视频| 伊人网综合高清在线播放| 国产真实内射老熟女久久久| 国产三级国产精品久久成人 | 亚洲中文国产字幕| 自拍偷拍亚洲首页| 1024你懂的日韩欧美人妻| 红桃在线观看av| 999精品视频在线观看精品| 国内久久久精品99| 亚洲精品久久久久久蜜臀| 天天干天天操天天射久| 欧美国产日韩成人一区二区三区 | 情趣视频在线国产| 欧美黑人xxxx猛交少妇| 欧美人妻vs中文字幕| 亚洲一区在线蜜桃| 自拍偷拍亚洲天堂精品| 日老熟女逼网视频导航| 一区二区三区欧美日韩| 日韩免费av在线观看激情| 亚洲一区二区 偷拍| 久草视频在线有精品| 国产精品亚洲欧美一级久久精品| 黄色午夜免费网站| 中文字幕人妻一区二区三区熟女| 99永久免费精品视频| 日韩电影亚洲专区天堂| 狠狠操狠狠干狠狠操狠狠干| 国产婷婷精品av在线| 狠狠操狠狠干97| 女同性恋亚洲av| 国产成人看片在线| 小明看看成人在线免费视频| 亚洲欧美日韩激情在线| 国内美女直播视频| 国产精品久久久久久精品香蕉| 国产精品久久久亚洲av| 91在线免费观看视频在线观看| 成人精品国产一级二级| 青青爽视频免费在线观看| 久久视频这里只精品| 婷婷亚洲综合久久| 日本五十路六十路熟妇| 蜜臀久久午夜小视频,| 国产一区免费在线视频观看 | 日韩美女中文字幕在线看| 亚洲精品无码中文字幕无码| 顶级少妇一区二区三区| 午夜免费观看视频一区二区| 色香视频亚洲自拍偷拍| 日本五十路六十路熟妇| 国产成人AV无码一二三区| 自拍另类亚洲欧美| 超碰资源免费在线| 最新亚洲国产高清激情| 免费中文字幕啪啪啪| 亚洲天堂成人在线观看| 97电视剧在线观看免费| 国产熟妇另类久久久久久| 久久九九免费精品国产| 4438x中文字幕| 久久免费又粗又长又硬又深又色 | 99久久精品国产av| 麻烦视频一区二区三区| 久久国产精品波多野吉衣av| 中国久久精品电影| av岛国网站在线观看| 日韩美精品美女毛片| 人妻一区二区久久中文| 九九热免费视频播放| 日本欧美三级高潮受不了| 天天爽夜夜爽人妻va| 欧美二区三区精品在线| 免费少妇一区二区三区| 97超碰在线高清| 色婷婷狠狠18禁久久久| 中文有码字幕在线| 大片一级黄片一级| av大片在线看亚洲| 黄色成年人在线观看| 国产精品v欧美精品v日韩| 欧美亚洲韩日一区二区三区| 日韩精品在线午夜| 国产亚洲精品久久久一区二区| 色综合久综合久久综合久鬼88 | 97资源超碰成人| 精品日韩视频在线观看| 亚洲另类欧美自拍| 男人操女人中国产视频| 中文字幕99精品| 777极品伊人久久久久久| 九九热在线视频精品1| 在线中文字幕在线中文| 欧美日韩色图一区二区| 91精品国产综久久久久| 国产视频97在线播放| 人妻 中文字幕 森泽佳奈| 尹人香蕉久久99天天拍久女久| 91热视频在线观看| 美女把逼给男人操| 欧美精产国品一区二区| 午夜在线视频播放网站| 亚洲第一页色自拍| 国产伦理精品av| 亚洲欧美国产麻豆综合| 欧美乱视频一区二区三区| 亚洲男人的天堂久久| 国产91熟女高潮一区二区| 国产精品视频一区二区三区16| 国内精品久久99人妻无| 日韩av最新在线| 日韩午夜福利视频合集| 伊人久久视频在线观看| 骚熟妇人妻中文字幕网站| 男女啪啪高清网站| www.狠狠视频.com| 欧美激情亚洲激情亚洲| 中文字幕一区在线精品| 人妻 中文字幕 森泽佳奈| 中文字幕久久j日| 国产精品成人免费视频观看| 日韩不卡视频一区| www.日产国产欧美com| 久久国产精品99精品国产| 久久婷婷视频一二三区| 国产亚洲精品av成人无删减| 中文字幕123一区二区三区| 日韩av在线不卡看| 成人av电影网站日韩| 俺去啦视频在线精品| 国产精品淫语av播放| 精彩av在线不卡播放| 美女把逼给男人操| 欧美一区二区三区综合网| 亚洲成网在线观看| 直接看的av天堂| 亚洲中文字幕久久精品品| av伊人网好吊妞| 91精品又粗又硬又爽少妇的视频| 极品人妻探花av| 久精品视在线观看视频| 丰满人妻综合一区二区三区 | 欧美成人亚洲另类图片小说网| 日韩精品视频在线视频看看| 超碰在线观看97视频| 亚洲春色男人天堂| 日本久久一区二区三区| 亚洲欧美自拍偷拍激情| 老鸭窝三区免费在线观看| 香蕉成人在线91| 亚洲啪啪啪一区二区三区| 亚洲在线一区二区在线观看| 无码人妻丰满熟妇区五十路| 日韩电影亚洲专区天堂| 最新亚洲国产高清激情| 亚洲日本熟妇高清| 日韩精品欧美嫩草久久99| 天天影视色最新色| 日本女优在线三区| av少妇人妻中文字幕| 日本妇女高潮视频| 国产精品99久久久久久天天| 奶头被吸得又大又黑np| 亚洲天堂成人网入口| 五月婷婷色激情网| 日韩在线精品亚洲| 精品免费污污网站在线观看| 久久久九九九精品视频| 久久亚洲欧美日本精品品| 色94色一区二区三区| 97狠狠狠狠狠狠狠| 日韩熟女一级片在线观看| 青青青操国产在线视频| 亚洲性感天堂欧美| 亚洲国产a∨天堂| 亚洲日产av一区二区在线| 亚洲男人av天堂精| 97电视剧在线观看免费| 97久久香蕉国产线看观看| 久久国产午夜精品| 亚洲 校园 春色 另类 激情| 国产精品久久久久久久久久精爆| 77777蜜臀精品久久综合| 国内偷拍视频久久久久久| 中文字幕色123| 国产精品熟女高潮久久99| 亚洲人妻自拍偷拍| 午夜美女免费福利| 日韩少妇一区二区三区四区| 性色av午夜精品福利在线观看| 99re视频免费热线观看| 2019成人在线视频| 麻豆一区免费爱爱视频| 中文字幕一级不卡| 国产一区二区在线激情欧美| 人妻 丝袜美腿 中文字幕| 国产免费观看久久久久久久久久| 婷婷亚洲综合久久| 亚洲在线久久伊人| 在线成人激情av| 国产又粗又猛又爽又黄的视频在线 | 国产人妻av在线看| 亚洲精品在线17| 69亚洲综合激情五月久久| 久久久综合网久久久综合网| 精品伊人久久免费视频| 尹人香蕉久久99天天拍久女久| 午夜美女诱惑福利| av最新在线中文天堂| 日韩在线一区二区三区精品| 精品黄色美女一二区| 久碰久摸久看在线观看| 成人精品国产一级二级| 超碰大香蕉在线一人| 国产成人h片在线观看| 国产精品一级999| 人妻 在线 二区| 国产成人AV无码一二三区| 国产日韩欧美二区视频| 农村人妻一区二区三区| 亚洲精品熟女自拍| 最大的黄色亚洲网站在线观看| 黄色理论片在线观看| 日本成人中出视频| 日韩欧美一区二区在线免费观看| 日本免费激情在线观看| 成人日本免费视频| 91高清在线观看一区| 日韩欧美成人av电影| 日韩av不卡在线看| 99一区二区三区精品人妻| 视频在线免费观看色| 校园春色激情另类| 国产一级aa特黄大片| 国产强上美女在线观看| 毛片av福利在线| 大香网伊人久久综合网20| 亚洲av少妇高潮150p| 色综合久综合久久综合久鬼88| 精品久久久久久五月天| 丰满人妻综合一区二区三区| 日韩一道本高清av| 在线高清蜜桃av| 96国产av传媒精品| 国产精品久久国产丁香花| 熟女乱一区二区三区四区| 伊人久久中文字幕av| 亚洲精品日韩免费观看| 亚洲视频亚洲视频| 日韩美女深夜网站| 久久久久久久久久免费观看视频| 国产一区视频免费观看| 国产视频一区 在线播放| 97精品人妻一区蜜桃| 亚洲五区四区三区二区| 欧美一区二区三区免费的网址| 99re视频免费热线观看| 久在线视频_老鸭窝在线视频| 动漫天堂同人av| 不卡视频无一区二区三区四| 亚洲伊人久久在线| 日本伦理在线一区| ysl蜜桃色7v| 在线观看日韩黄色蜜桃| 国产情侣自拍成人| 99久久精品国产av| 五月婷婷色激情网| 极品人妻探花av| 国产一区二区在线激情欧美| 日韩亚洲在线成人| 国产 欧美 日韩 成人| 久久 91 欧美 精品| 国产欧美日韩综合区| 91麻豆精品国产自产在| 丰满熟女少妇午夜福利视频| 嫩草九九九精品乱码一二三| 激情av五月婷婷| 国产精品99久久久久久网站| 中文一区二区三区在线播放| 伦理片一区二区三区在线观看| 99只有精品在线观看| 97狠狠狠狠狠狠狠| 亚洲精品丝袜美腿久久| 欧美日韩国产激情不卡| 日韩三级 国产精品| 99热只有国产在线精品| 日韩国产欧美激情在线视频| 性高潮久久久久久久久免费| 在线观看日韩黄色蜜桃| 变态另类天堂在线播放| 97人人模人人爽人人喊38| 国产精品一级999| 日韩 欧美 丝袜| 国产人妻精品中文字幕| 最新欧美激情一区二区| 亚洲综合自拍成人偷拍网站| 麻豆精品国产传媒美女网站| 成人国内精品久久久久一区| 尤物在线观看视频av| 国内自拍全部视频在线| 认你日爽在线视频| 大香网伊人久久综合网20| 久久综合日韩欧美| 国产精品视频福利在线| 99偷拍精品一区二区| 大香蕉伊人久久草| 新老鸭窝在线视频| 欧美情色免费视频| 天天干天天日天天操天天爽| 伊人网综合高清在线播放| 久久精品只有精品免费观看| 99国产小视频在线播放| 热久久77这里有精品综合久久| 欧美精品久久久久久无| 五月亚洲婷婷亚洲| 天天干天天综合色| 99久久国产精品久久久久| 久久精品久久久久久久久久| 亚洲无av码一区二区三区| 97视频在线播放| 伊人网综合高清在线播放| 亚洲av日韩av成人在线| 亚洲另类伦春色综合小| 麻豆av精品在线| 日韩母乳女优激情视频在线观看| av中文字幕在线播放| 亚洲天堂成人网入口| 蜜桃一区二区三区在线观看视| 啄木乌av一区二区三区| 亚洲天堂国产久久| 精品欧美日韩免费| 伊人久久中文字幕av| 自拍视频一区在线| 久久66热人妻偷产精品9| 国产精品久久久久免费播放| 国产成人午夜电影在线观看免费 | 免费观看性感美女| 国产精品亚洲av三区| 国产精品久久久久免费播放| 狠狠综合久久综合88亚洲| 97国产精品影院在线观看| av在线亚洲最大的| 麻豆精选在线播放视频| 人妻熟妇av在线| 国产精品黑丝美腿美臀| 欧美男人女人在线视频| 中文字幕一区二区三区四区二区| 国产69精品久久久/| 国产一区精品视频免费播放| 91精品老司机视频网站| 婷婷亚洲综合久久| 亚洲人成精品久久久久| 国产黄色一级大片全集| 天天爽夜夜爽人妻va| 亚洲天堂嗯啊嗯啊| 欧美日韩在线视频在线| rct378在线中文字幕| 亚洲欧美日韩激情视频| 欧美亚洲成人动漫在线| 精品国产91久久久久久久| 熟女潮喷白浆x88av| 丁香欧美欧美欧美欧美欧美| 日韩av在线激情| 亚洲天堂成人网入口| 亚洲丝袜中文字幕在线观看| 伊人网综合高清在线播放| 一级特色特级黄大片| 日本伊人伊人伊人| 欧美日韩亚洲成人一区| 日本伦理视频在线| 久久婷婷视频一二三区| 日本二级三级在线观看| 国产福利在线观看91| 中文字幕制服丝袜在线电影| 一区三区精品视频在线观看| 中文字幕在线三级| 男人日女人的逼的视频| 国产精品欧美日韩在线观看一区| 国产亚洲自拍色图| 日韩女人小便视频| 中文字幕av三级免费| 97免费公开视频观看| 人妻素人中出一区二区三区| 日韩欧美一区二区在线免费观看| 中文字幕亚洲天堂| 成人黄色性生活一级片| 色哟哟在线观看永久免费视频 | 久草这里只有精品99| 欧美日韩成人在线高清| 成人伊人精品色xxxx视频| 久久久久久国产精品av| 俺去啦视频在线精品| 在线观看福利av午夜| 偷拍自拍亚洲专区| 国产欧美日韩在线观看免费| 黄色一级片人和狗| 欧美日韩操操操操操| 国产在线av小视频| 一区二区三区欧美日韩| 国产日韩欧美三级在线| 中文字幕人妻在线| 丝袜美腿免费在线| 午夜蜜臀一区二区三区四区五区| 欧美日韩亚洲中文色| 激情av五月婷婷| 国产av一区二区三区成人| 91国产精品久久久久| 午夜精品久久久久久久久久久久久| 日韩免费观看v.| 绯色av一区二区三区在线观看| 国产精品一一色哟哟| 在线亚洲无av码| 熟女人妻久久中文字幕| 97免费公开视频观看| 亚洲成av人片一区二区久久久 | 黄色午夜免费网站| 国产av专区网站大全| 亚洲欧美另类视频| 亚洲国产婷婷六月丁香伊| 23久久精品中文字幕人妻| 亚洲三级激情在线观看| 日韩美女精品视频| 欧美国产精品久久九九| 日本欧美三级高潮受不了| 久久免费又粗又长又硬又深又色| 国产又黑又粗又黄又大| 欧美精品mv在线播放观看 | 亚洲情色伦理在线| 少妇熟女一二三区| 97特黄一级中文字幕在线| 丰满年轻岳中文字幕一区二区| 日韩av最新在线| 超碰激情免费在线播放| 亚洲免费看125个视频 | av人妻精品一区二区三区| 国产麻豆激情图区在线| 国产高清av网址免费| 激情五月婷婷婷婷婷婷婷| 国产情趣丝袜高跟av色| 99在线午夜日韩视频| 五月婷婷视频免费观看| av影音在线不卡| 丝袜人妻精品一区二区三区| 99一区二区三区精品人妻| 国产强上美女在线观看| 亚洲最大熟妇人妻| 婷婷综合在线五月天| 视频一区二区蜜桃| 人妻一区二区久久中文| 日韩蜜臀人妻素人精品在线观看 | www国产亚洲精品久久麻豆| 91精品国产综久久久久| 日韩av不卡在线看| 久久婷婷成人精品国产电影| 日本免费激情在线观看| 欧美熟妇大阴蒂高潮系列| 天天爽夜夜爽人妻va| 国产 欧美 日韩 成人| 日本最新在线不卡免a费视频| 精品人妻日日夜夜操| 婷婷国产成人在线| 91在线播放 精品| 中文字幕天堂av.| 伊人久久视频在线播放| 欧美日韩激情文学| 日韩欧美成人av电影| 青青青青啪啪啪啪网站| 大香蕉av在线免费观看| 日日夜夜免费看精品视频| 国产伦精一区二区三区| 久久精品国产亚洲av麻豆看片| 国产av高清无限看| 日韩一区二区在线观看视频| 日韩精品中文字幕资源| 日韩 午夜 免费| 亚洲一区两区三区四区| 亚洲第一蜜桃av| 国产综合一区久久91| 日日夜夜免费看精品视频| 精品久久久久久五月天| 色婷婷久久综合久色| 国产亚洲欧美视频二区| 黄色污污污免费在线观看网站| 欧美 日韩 亚洲 二区| 国产成人AV无码一二三区| 欧美日韩性视频播放| 九九热播这里只有精品| 国产高清av网址免费| 日韩高清無碼天堂| 大屁股熟女风间由美| 天天操美女综合网| 就爱操在线视频观看| 日韩丝袜人妻中文字幕| 高清在线 中文字幕| 国产精品欧美日韩在线观看一区| 熟妇 人妻 中文| 伊人久久网36蜜桃| 黄色强奸片免费观看视频免费看| 日韩三级电影免费久久| 久久久96人妻精品蜜桃hd| 日韩一级av电影| 欧美一区二区三区四区在线| 亚洲一区在线蜜桃| 人妻超碰在线观看| 久久人妻精品二区| 自拍伦理视频在线观看| 国产熟女露脸自拍| 欧美精品一区二区免费开放| 国产av在线播放网站| 99久国产精品午夜性色福利| 国产中文在线二区三区免| 日韩国产主播av在线| 在线人妻视频观看| 国产亚洲欧美日韩国产精品三区| 亚洲黄页在线视频| 高清有码中文字幕在线观看| 久久99蜜桃精品视频| 国产第一影院草草影院久久| 日韩av在线1区| 黄色大片长久网站| 97视频都是精品| 91精品久久久久含羞草| 国内自拍全部视频在线 | 亚洲男人av天堂精| av在线一区二区三区地区| 激情五月婷婷综合色视频| 99热这里只有精品在线| 99久久九九社区精品| 古代黄色片在线观看| 日韩精品色图在线| 18禁美女国产美女网站| 麻烦视频一区二区三区| 国产亚洲欧美视频二区| 久久午夜激情视频| 超碰九七在线免费观看| 国产一区二区三区女人的床叫声| 蜜桃视频一区二区免费| 天天日天天舔y透| 日本熟妇肉体裸交| 蜜桃一区二区三区在线观看视 | 国产一区二区三区亚洲欧美| 中文字幕人妻xxxx| 美女视频黄免费的亚洲男人天堂| 在线视频一区二区观看| 亚洲精品久久久久综合| 一区二区三区四区五区国产av| 久碰久摸久看在线观看| 91在线精品在线| 日本免费久久精品| 91亚洲人妻一区二区三区| 午夜av网站观看| 欧美日韩激情免费在线视频| 日韩中文字幕在线观看乱码| 在线看成人a v| 日韩va欧美激情在线| 精品亚洲精品国产一本大道| 日韩三级电影免费久久| 网页端在线聊天室| 日本精品九九久久精品一本| 99久久综合精品五月天| 国产av在线播放网站| 欧美在线午夜观看| 丝袜美脚av一区| 色爱综合久久一区二区三区蜜桃臀 | 19国产精品麻豆| 国产一区区二区三区| 五月婷婷久久中文| 曰曰摸夜夜添av老司机蜜桃视频| 亚洲一区乱码在线观看| 九九热在线视频精品1| 伊人久久网36蜜桃| 欧美日韩少妇熟女| 色偷偷888欧美精品| 中国久久精品电影| rct378在线中文字幕| 男人日女人的逼的视频| 色就是色综合欧美色| 成人动漫在线观看播放| 蜜臀av在线玖一区| 91精品激情在线视频| 欧美乱视频一区二区三区| 91中文字幕亚洲资源| ysl蜜桃棕调色| 欧美日韩色图一区二区| 日韩人体高清精品一区二区三区 | 国产精品v白虎逼| 国产欧美一区视频在线观看| 色哟哟在线观看永久免费视频| 4438x中文字幕| 超级碰人妻香蕉在线97| 中文字幕人妻熟女一区二区三区| 国内精品久久久久久精品视频 | 成人影院久久久久久久久一区| 青青青草草草久草| 97特黄一级中文字幕在线| av伊人网好吊妞| 亚洲情色伦理在线| 久久伊人青青草大香蕉| 国产av 一区二区三区| 亚洲天堂成人网入口| 日本老女人性生活视频| 日韩av永久免费观看| 亚洲国产成a人片77777| 国产第一影院草草影院久久| 99一区二区三区精品人妻| 国产视频欧美一区二区| 国产伦精品一区二区三区视频9| 2020国内自拍视频| 红桃在线观看av| 国产97综合久久久| 日韩亚洲欧美综合一区二区 | 天堂网最新中文字幕| 91国产精品久久久久| 黑丝少妇的诱惑在线观看| 婷婷亚洲综合久久| 日韩中文乱码字幕| 美腿丝袜综合在线日韩| 久久久久久久久波多野高潮| 97人妻免费视频精品| 亚洲视频成人在线播放| 中文人妻熟妇精品乱又伧不卡| 91精品国产一二三产区区别在哪| 最新国产精品手机网站| 色婷婷美国农夫综合激情亚洲| 91九色porny国产| 日韩无人区一卡2卡3卡4卡| 亚洲天堂最大影院| 久久久久久精品成人| 欧美一区二区三区四区在线| 日韩一区二区在线观看视频| 在线中文字幕国产精品| 日韩在线中文字幕在线| 精品欧美日韩在线观看| 手机在线日韩av| 日韩欧美一区二区三区人妻| 99热这里有国产| 黄色午夜免费网站| 青青青青青青青青青青青青青| 国产强上美女在线观看| 熟女人妻久久中文字幕| 激情中文字幕视频| 日韩久久精品免费一区二区| 欧美男人女人在线视频| 99久久99视频只有精品| 国产精品一一色哟哟| 亚洲欧美自拍偷拍激情| 久久伊人青青草大香蕉| 亚洲另类欧美自拍| 久久视频这里只精品| 天堂男性av在线| 成人av电影网站日韩| 色婷婷a区一区二区三区| 日韩啊v视频在线| 成人理论在线播放| 视频一区二区三区免费观看| 91亚洲视频在线观看黄| 婷婷综合五月激情网| 日韩三级电影免费久久| 日韩丝袜情趣美女图片| 一本色道久久88亚洲| 日韩一区二区三区四区不卡网| 91污在线免费观看视频| 日韩av在线1区| 日韩精品亚洲性图欧美| 中文字幕亚洲综合色| 可以试看的黄大片| 国产美女蜜臀av怡红| 麻豆av熟女少妇精品| 精品国偷自产一区二区三区免费| 日韩亚洲欧美高清视频| 三级有码在线观看| 婷婷91人妻精品一区二区三区| 91精品伊人久久久大香线蕉91| 亚洲天堂成人在线观看视频网站 | 欧美伊人亚洲伊人色综合动图| 91在线视频亚洲| 认你日爽在线视频| 色婷婷美国农夫综合激情亚洲| 亚洲精品在线小视频| 亚洲av极品在线| 伦理疯狂精油按摩| 亚洲一区二区av在线网站| 黄色强奸片免费观看视频免费看| 国产91品久久久久久久久| 日本免费观看一区| 极品视频一区在线观看| 国产熟女一区二区91| 婷婷只有在线精品视频| 国产91熟女高潮一区二区| www国产亚洲精品久久麻豆| 亚洲婷婷精品av久久蜜桃久久| 久久久久久久日本综合| 天天干天天综合色| 日本伦理视频在线| 亚洲国产日韩不卡| av资源在线一区二区三区| 调教女m在线观看| 日本在线高清视频| 国产又大又黄又粗在线观看| 2020午夜免费福利| 日韩精品毛片免费播放蜜臀| 99热这里只有精品在线| 精彩av在线不卡播放| 亚洲综合自拍成人偷拍网站| 日本女优与黑人特级| 天天天操天天干天天日| 国产精品久久人人添| 亚洲一区成人动漫在线观看| 亚洲国产成a人片77777| 久久久久久人妻免费视频o| 视频免费在线你懂的| 97超碰在线高清| 日韩伦理在线观看一区视频| 日韩人妻少妇中文字幕| 日韩国产主播av在线| 日韩超碰97在线观看| 青青国产精品最新网址| 成人看黄色录像片| 都市激情 校园春色 中文字幕| 日韩色黄电影在线观看| 麻豆影视精品在线观看| 极品人妻口爆颜射| 欧美日韩亚洲成人一区| 蜜桃久久久久久欧美| 亚洲中文字幕日本| 久久久久久 九色av| 成人黄色伦理网站| 在线97视频观看| 偷拍视频你懂的一区二区三区 | 日韩美精品美女毛片| 久久久蜜桃精品人妻一区| 亚洲人妻一区二区在线观看| 亚洲av久久精品在线| 天天操天天透天天射| 精品在线激情av| 黄色一级成人大片| 日韩亚洲丝袜美腿久久| 丰满女人床上激情久久| 人妻av中文字幕网| 日韩熟女少妇高清视频| 99久国产精品午夜性色福利| 亚洲av熟妇在线| 四虎av在线观看| 久久久蜜桃成人网| 国产精品久久久久久人妻爽| 日韩中文字幕激情在线| 人妻精品一区二区久久| 午夜激情福利大片| 久久久久久久久久免费观看视频| 一区二区三区四区av| 久久99 国产精品| 亚洲欧美国产免费| 特黄特色的大片免费看| 青青手机国产视频| 日韩三级电影一区二区三区| 一区三区精品视频在线观看| 亚洲成人人妻一区| 亚洲av少妇高潮150p| 中文字幕人妻久久不卡| 亚洲免费观看毛片| 亚洲乱码国产乱码精品精可以看| 蝴蝶综合久久久久久久久久| 精品丝袜人妻久久| 成人中文字幕专区| 神马一区二区三区伦理片| 日本不卡无吗在线播放| 青青视频成人免费完整版| 自拍偷拍亚洲天堂精品| 老司机中文视频网| 99只有精品在线观看| 蜜臀av在线玖一区| 91亚洲视频在线观看黄| 国产精品一级999| 色香视频亚洲自拍偷拍| 国家五a级久久久久久黄片| 中国精品久久久久久| 人妻 在线 二区| 加勒比在线视频在线播放| 久久精品亚洲精品无码白云tv| 亚洲国产天堂在线| 激情av五月婷婷| 国内偷拍视频久久久久久| 人妻字幕av一区二区三区| 午夜免费观看视频一区二区| 中文字幕不卡一区二区三区| 狠狠综合久久综合88亚洲| 日本精品高清久久久| 噜噜视频在线播放视频| 色婷婷激婷婷深爱五月老司机| 久久精品国产露脸对白| 亚洲伊人久久在线| 亚洲精品在线观看av密乳av| 2020午夜免费福利| 丝袜美腿诱惑福利| 亚洲欧洲av天堂| 国产香蕉久久精品免费| 国产精品久久久久久久久av | 日韩高清av在线免费观看| 看久了久久久久久久久久| 99国产小视频在线播放| 91小情趣制服肥臀九色| 女同性猛交xxxx| 午夜精品尤物麻豆一区二区无限| 亚洲成人偷拍av| 日韩中文字幕在线观看乱码| 亚洲一区二区三区四区在线网站| 日韩av手机免费在线观看| 中文字幕欧美极品| 日韩精品色图在线| 97国产三级精品在线| 2021狠狠狠狠狠| 女同性猛交xxxx| 色婷婷欧美亚洲激情综合另类在线| 精品丝袜人妻久久| 欧美日韩国产最新久久| 亚洲av日韩av成人在线| 97免费公开视频观看| 国产精品久久久久精品三级a| 52av成人久久国产一区| 超碰免费免费人妻97| 91青青草这里只有精品| 国产 91 九色 精选| 国产视频在线观看播放| 国产免费播放一区| 黄色强奸片免费观看视频免费看| 欧美日韩久久理论视频| 人人妻人人澡人人爽人人精品直播| 日韩欧美在线观看二区| 啪啪国产视频自拍| 国产欧美在线亚洲| 尤物av在线播放| 中文人妻精品一区二区三区四区 | 国产麻豆丝袜美腿诱惑在线播放| 国产一区二区欧美视频| 色综合久久中文综合久久| 免费a级黄片在线观看| 深夜激情小视频在线观看| 日韩人妻精品一二三| 天堂男性av在线| 天天插天天日天天啪| 97精品人妻一区蜜桃| 熟女阿b老熟女一区| 熟妇人妻中出视频| 欧美日韩av一区=区三区| 国内偷拍视频久久久久久| 人妻一区两区三区四区| 欧美日韩久久理论视频| 亚洲国产自拍在线| 91色综合综合热五月激情| 一区二区电影成人| 美女黄频蜜桃av| 熟女乱一区二区三区四区| 日本少妇激情视频| 青青青在线视频人视频| 亚洲一区二区人妻| 日本熟妇乱一区二区三区| 国产精品黑丝美腿美臀| 噜噜视频在线播放视频| 亚洲最大熟妇人妻| 国产情趣丝袜高跟av色| 日韩美女精品视频| 少妇被爽到高潮喷水久久| 欧美日韩国产最新久久| 国产精品高潮呻呤久久av| 17c久久精品国产亚洲| 日韩国产成人一区| 亚洲女人的av天堂| 国产视频1区二区三区| 大香蕉av网站在线观看| 97免费精品97久久久久久97| 国产亚洲欧美视频二区| 日本乱码视频在线播放| 中文字幕色123| 88成人美女女内射| 国产精品久久天干天干| 国产一区二区三区自拍欧美| 新老鸭窝在线视频| 欧美日韩性视频播放| 中文字幕欧美极品| 国产乱码一区二区三区四区| 在线观看国产高清精品| 九九热视频这里只有精品在线观看 | 美女黄频蜜桃av| 九九综合九色综合98| 欧美影院一区二区三区| 久久精品久久久久久久久久| 中文字幕av人妻呻吟| av人妻精品一区二区三区| 精品久久国产精品久久| 青青青青青青青青青青青操操| 91性高久久久久久久久| 亚洲中文字幕久久精品品| 午夜精品一区二区三区蜜桃| 中文精品久久久久人妻不| 亚洲三级激情在线观看| 在线97视频观看| 欧美 日韩 亚洲 二区| ysl蜜桃色14| 国语自产拍在线观看视频| 日本久久久久久久国产精品| 亚洲av黄久久久| www国产亚洲精品久久久| 欧美成人破处视频| 久久久久日本精品无码天美传媒| 一区二区四区欧美| 欧美黑人xxxx猛交少妇| 嫩草九九九精品乱码一二三| 国产av一区二区三区成人| yy8098国产av久久| 黄色片网站国产精品| 色偷偷888欧美精品| 久久综合日韩欧美| 激情人妻一区二区三区| 人妻一区二区三区精品高| www国产亚洲精品久久麻豆| 日本久久久久久久国产精品| 青青操视频在线观看免费观看| 日本高清中文字幕久久| 一级成人黄色影视| 日韩欧美一区二区三区不卡| 免费97人妻一区二区三区| 在线 人妻 视频| 丁香六月天久久婷婷| 美女网站视频大全| 91精品视频在线观看免费版| 99久久国产精品久久久久| 欧美精品在线视频| 亚洲乱码精品乱码精品中文| 亚洲丝袜中文字幕在线观看| 日韩欧美中文字幕第一页| 黑丝少妇的诱惑在线观看| 中文字幕一区在线精品| 91久久美女高潮喷水| 国产强上美女在线观看| 亚洲欧洲av天堂| 国产精品色婷婷久久58| 亚洲视频区1000| 少妇人妻在线一区二区| 高清在线 中文字幕| 极品少妇高潮久久久久久久久| 在线观看福利av午夜| 激情内射一区二区三区| 乱码欧美中文字幕日韩| 国产免费精品久久久| 久久九精品综合丝袜影视精品| 日韩欧美亚州综合| 日韩亚洲在线成人| 五月亚洲婷婷亚洲| 我要看黄色一级影视片| 国产av一区二区三区成人| 91极速版免费视频| 精品人妻少妇久久久久久| 国产日韩高清一区二区| 精品久久久久久国产视频| 成人在线免费观看久久视频| 国产福利小视频在线观看免费 | 欧美精品在线观看网址| 亚洲天堂成人网入口| 久久久久久久久波多野高潮| 久久精品国产亚洲av麻豆软| 国产熟妇另类久久久久久| 国产婷婷精品av在线| 在线 亚洲 精品| 日韩av在线大片| 亚洲天堂成人在线观看视频网站| 丝袜人妻av中文字幕| 中文字幕日本精品免费| 最新亚洲国产高清激情| 91精品视频在线观看免费版| 国产精品成人免费视频观看| 美女福利视频午夜| 日韩人妻专区一区二区| 日韩一区不卡二区| 国产精品人妻系列23p| 伊人久久视频在线观看| 精品人妻熟女一区| 调教女m在线观看| 精品一区二区三区 蜜臀av| 极品视频一区在线观看| 91精品国产综合久蜜臀| 欧美熟妇久久久久久久久久久| www国产亚洲精品久久久| 99热精品夜夜爽伊人| 人妻中文字幕一区三区| 欧美二区三区精品在线| 天天舔,天天做,天天爽| 国产精品久久久精品久久| 中文字幕人妻aaaaa| 最新精品国产精品1| 午夜8050网站二级| 欧美另类老熟妇猛交| 又黄在线免费观看视频| 日韩亚洲欧美综合一区二区| 国产又黑又粗又黄又大| 国产精品久久久久久av大片| 日本少妇激情视频| txtv在线视频| 国产欧美日韩精品一区二区| 国内久久久精品99| 久草视频播放在线| 日韩欧美亚洲精品人妻| 日老熟女逼网视频导航| 中文字幕人妻综合网| 国产精品99久久久久久有的能看| 亚洲国产精品va在线观看www| 超碰在线97中文字幕在线观看| 亚洲精品9999久久久久| 久久久无码av一区二区三区| 欧美一区二区三区免费的网址| 日韩人妻专区一区二区| 国产人伦人妻亚洲| 古代黄色片在线观看| 青青草原精品视频在线观看| 国产精品综合久久桃花| 亚洲性色av网站| 久久人妻大香蕉艺儿网| ysl蜜桃棕调色| 出轨少妇自白小说| 人人妻人人]人人澡欧美一区| 久久国产成人精品a| 中村智惠巨乳av| 黄色强奸片免费观看视频免费看 | 久久久久久一级二级三级| 欧洲精品无码一区二区三区视频| 国产视频欧美一区二区| 国产欧美日韩精品电影免费| 热久久77这里有精品综合久久| 日本熟妇肉体裸交| 国产精品很黄很色很爽的网站| 日韩最新视频播放| 肥屁股高潮迭起一区二区的视频| 中文字幕原创国产ol| 亚洲av综合av一区二区综| 色av色婷婷18人妻久久久| 伊人久久视频在线播放| 超碰在线观看97视频| 国产人妻av在线看| 久久少妇高潮视频免费| 久久久无码av一区二区三区| 黄色成人在线私拍| 中文字幕av久久爽伊人一级| 国产一区激情视频在线播放| 国产欧美1区2区3区| 青青操在观看视频| 国内在线视频精品一区美女| 欧美国产午夜一区二区| 色综合综合色综合色综合色综合| 色视频在线一区二区三区| 日本伦理视频在线| 91在线播放 精品| 红桃在线观看av| 窝人体色www视频婷婷| 久久久久久久久久久久少妇| 亚洲精品丝袜美腿久久| 亚洲小视频在线观看免费播放| 国产亚洲精品美女久久久| 午夜精品久久久久久久91蜜桃臀| 精品亚洲午夜久久久久四季| 91精品国产综合久蜜臀| 久久亚洲天堂成人精品| 99久久国产综合精品久久国产| 日本欧美三级高潮受不了| 国产日韩欧美三级在线| 精品人妻少妇久久久久久| 亚洲精品乱码久久久久蜜桃网站| 色婷婷综合久久久精品视频| 久久女人撒尿视频| 精品视频久久一区二区三区四区| 国产视频欧美一区二区| 日韩午夜精品短视频| 亚洲亚洲亚洲天堂天堂天堂| 亚洲熟女午夜毛片av毛片| 人人妻人人爱人人澡| 中文av字幕在线观看一区| 人人妻人人爽97| 久久精品熟女俱乐部| 日韩高清無碼天堂| 亚洲综合动漫图片| 欧美视频观看99| 国产熟女啪啪精品一区二区三区| 999久久精品视频在线| re久久99热国产| 中文精品久久久久人妻不| 欧美成人破处视频| 亚洲av久久精品在线| 日韩中文乱码字幕| 久久国产午夜精品| 奶头被吸得又大又黑np| 6666成人在线| 大香蕉伊人免久久| 美女黄频蜜桃av| 超碰97免费公开在线人妻| 色婷婷久久综合久色| 美日韩成人一级免费黄色片| 国产精品久久久久噜噜噜| 国产情趣丝袜高跟av色| 日本东京热狠狠干视频| 国产蜜桃av在线观看| 久久这里只有精品2023| 日本少妇熟女中出| 黑人上司魅惑人妻电影| 日本二级三级在线观看| 九九七视频在线观看| 在线观看国产高清精品| 久久日韩精品中文字幕人妻熟女| 国产精品原创中文巨作av| 亚洲 成人 av 在线| 国产三级伦理在线观看| 最新国产精品手机网站| 亚洲欧美日韩一区另类| 国产中文在线二区三区免| 日韩色黄电影在线观看| 免费在线观看亚洲黄色| 日韩毛片免费播放| youtube没有中文字幕| 国产自拍偷拍日韩精品| 九九热在线视频精品1| 亚洲av懂色av| 日本高清中文字幕久久| 日韩啊v视频在线| 五月婷婷六月在线观看| 国产高跟丝袜av| 日韩av另类在线| 国产一区视频免费观看| 亚洲女人的av天堂| 国产高跟丝袜av| 午夜久久福利电影网| 中文字幕久久一二三四区| 人妻中文字幕一区三区| 日韩免费视频播放| 日本伊人伊人伊人| 中文字幕日韩人妻视频一区| 中文字幕久久中文字幕综合网| 日韩特级片中文字幕| 大香蕉伊人久久草| 91污在线免费观看视频| 精品久久国产精品久久| 青青操在观看视频| 亚洲国产麻豆综合一区| 国产三级国产精品久久成人| 久久人妻精品二区| 东京热人妻视频在线观看| 亚洲精品免费综合| 蜜桃视频一区二区精品| 久久精彩视频免费看| 91红桃在线观看| 日本中文字幕在线观看免费| 日韩欧高清视频在线| 国产一区二区三区女人的床叫声| 熟女91n一区二区三区| 开心五月婷婷丁香婷婷| 欧美一区二区三区激情久久| 欧美 成人 一区 二区| 丝袜 成人 av| 精精品人妻一区二区| 亚洲国产久久精品| 99er视频,这里有精品九九| 天天干天天日天天操天天色天天射| 国产亚洲精品久久久一区二区 | 亚洲av日韩av成人在线| 麻豆影视精品在线观看| 999zyz玖玖资源站成人精品| 五月婷婷激情综合少妇| 亚洲岛国av在线| 日本成年中文字幕| 中文字幕123一区二区三区| 在线观看亚洲成人av电影| 亚洲经典1区2区3区| 日韩欧美一区免费电影| 久久一本色道综合六月天| 91热视频在线观看| 国产剧情福利在线播放| 国产激情怍爱视频在线| 亚洲天堂嗯啊嗯啊| 中文字幕av人妻网| 午夜免费观看国产视频| 精品人妻一区二区区中文| 国产亚洲精品av成人无删减| av在线亚洲最大的| 国产 日韩 精品在线观看| 亚洲 校园 春色 另类 激情| 国产一区二区三区香蕉| 蜜臀久久99精品久久久兰草影| 91精品国产麻豆自产在线| 日韩午夜福利视频合集| 国产精品一一色哟哟| 视频免费在线你懂的| 黄页网站网址在线观看| 国产乱老熟视频乱老熟女国| 国产成人AV无码一二三区| 国产欧美1区2区3区| 亚洲精品自拍产在线观看| 国产91在线播放小黄鸭| 亚洲国产日韩不卡| 91精品国产麻豆自产在线| 婷婷六月亚洲综合| 国产精品欧美一区二区三区不卡| 欧美日韩成人在线高清| 1024人妻熟女一区二区三区| 国产 欧美?亚洲?日韩视频| 999久久久蜜桃| 岛国精品少妇一区二区三区| 中文字幕乱码视频欧美| 人妻素人中出一区二区三区| 亚洲成天堂人动漫| 日韩欧高清视频在线| 日韩av欧美av二区| 日韩精品欧美嫩草久久99| 久久久久大香青草精品综合| 日韩欧美亚洲精品人妻| 亚洲综合制服丝袜另类在线| 熟女阿b老熟女一区| 高清有码中文字幕在线观看| 一区二区电影成人| 狠狠操狠狠干狠狠操狠狠干| 亚洲经典 中文字幕| 欧美乱视频一区二区三区 | 亚洲人妻熟女一区二区三区| 成人理论在线播放| 亚洲一级做a爰片| 91在线在线免费视频| 久久国产av人人做人人爽| 视频一区视频二区中文精品 | 国产乱品免费一区二区三区视频| 青青操视频在线观看免费观看| 久久综合日韩欧美| 国产精品吴梦梦视频| 超碰九七在线免费观看| 人人妻人人]人人澡欧美一区| 日韩色图欧美视频| 国产黄色一级大片全集| 日韩欧高清视频在线| 国产人妻av在线看| 亚洲精品又黄又爽的视频| 国产成人AV无码一二三区| 熟妇人妻丰满激情视频| 色香视频亚洲自拍偷拍| 婷婷国产人妻一区二区三区| 91国自产精品一区二区三区| 日韩中文字幕美女丝袜诱惑| 精品少妇高潮涩涩av| 黄色成年人在线观看| 国产自拍免费在线观看视频| 黑人中文字幕一区二区| 精品视频久久一区二区三区四区| 二区三区精品在线观看| 性生活久久久久久久久| 中文字幕一区在线精品| 97一区二区三区人妻免费| 欧美成人破处视频| avove在线视频| 亚洲精品免费综合| 一道久久久综合狠狠| 欧美精品视频一二三| 国产高清av网址免费| 超碰激情免费在线播放| 日韩色黄电影在线观看| 4438x中文字幕| 久久热这里只有精品5| 精品日韩视频在线观看 | 大香蕉伊人久久草| 国产久久精品视频在线观看| 久久精品只有精品免费观看| 国产人伦人妻亚洲| 五月亚洲婷婷亚洲| 99精品欧美一区二区三区蜜桃| 亚洲精品高潮呻吟久久av| 国产区在线观看视频全网yin乱| 亚洲欧美国产免费| 精品人妻一区在线视频| 国内美女直播视频| 91国产免费视频国产免费| av一区中文字幕在线| av网站软件在线播放| 成人国内精品久久久久一区| 91捷克街头在线播放| 蝴蝶综合久久久久久久久久| 久久久久大香青草精品综合| 国产亚洲欧美日韩国产精品三区| 伊人久久网36蜜桃| 日韩母乳女优激情视频在线观看| 国产福利小视频在线观看免费 | 玩弄超骚少妇一区二区三区| av老司机亚洲精品天堂| 美女网站视频大全| 人妻精品中文字幕在线| 欧美国产午夜一区二区| 精品人妻日日夜夜操| 亚洲毛片在线播放| 国产一区二区视频麻豆| 99久久精品国产亚洲av热热爱| 亚洲国产精品va在线观看www | 日本乱码视频在线播放| 日本黄色操碌缬巴| 日韩 欧美 丝袜| 国产精品亚洲欧美一级久久精品| 人妻熟女中文av| 久草大香蕉人与兽| 日本精品一区二区三区在线精品| 国产精品va一级二级三级| 99永久免费精品视频| 少妇高潮久久久久丙内射| 免费人人潮人人爽一区二区| 最新日韩在线观看视频| 52av成人久久国产一区| 日韩欧美亚洲精品人妻| 国产视频在线观看播放| 成人一级视频在线播放| 国产一级aa特黄大片| 91碰碰成人免费视频| 国产欧美日韩综合区| 中文字幕偷拍av| 亚洲精品自拍产在线观看| 亚洲在线一区二区在线观看| 激情边亲边摸视频| 亚洲熟女一区二区三区电影| 青青草国产在线免费观看 | 日韩色黄电影在线观看| 三级有码在线观看| 日韩欧美亚州综合| 亚洲视频亚洲视频| 日韩美女毛片午夜剧场| 中文人妻熟妇精品乱又伧不卡| 一本大道久久a久久综合精品| 亚洲天堂成人网入口| 成人av欧美在线观看| 欧美三级在线免费观看| 国产精品高清在线观看| 丝袜人妻诱惑在线| 23久久精品中文字幕人妻| 亚洲经典1区2区3区| 日韩中文乱码字幕| 中文字幕偷拍av| yeye38亚洲综合网久久| 中文字幕日韩一二三区视频| 蜜臀 av 一区二区| 丰满熟女浓毛大hd| 好看的av网站中文字幕| 最新国产激情视频| 美女精品福利视频在线观看| 精品少妇高潮涩涩av| 中文人妻熟妇精品乱又伧不卡 | 国产91精品福利在线观看| 国产 日韩 精品在线观看 | 亚洲天堂国产精品区| 亚洲最大综合久久网成人| 日本黄色日比视频| 91亚洲人妻一区二区三区| 亚洲中文av播放| 亚洲精品高清一二| 1024人妻熟女一区二区三区| 日韩欧美亚洲精品人妻| 在线视频国产香蕉岛国| 成人精品国产一级二级| 一区二区三区精品精品| 中文乱码人妻一区二区三区 | 国产一区二区精美视频| 一区二区三区内射少妇| 国产一区二区在线校花| 森泽佳奈视频一区二区三区| 黄色理论片在线观看| 丝袜人妻精品一区二区三区| 欧美精品国产字幕| 久久成年人免费网站| 日韩一级av电影| 日韩丝袜美腿av| 自拍偷拍亚洲天堂精品| 人妻中文字幕一区三区| 森泽佳奈视频一区二区三区| 青青青青久久精品国产首| 亚洲一区两区三区四区| 午夜激情免费视频| 日韩国产av大全| 熟女人妻制服丝袜中文字幕| 日韩中文字幕在线第一页| 免费一区二区风骚徐娘| 日韩啊v视频在线| 91精品又粗又硬又爽少妇的视频| 亚洲一本一道一区二区三区| 熟女潮喷白浆x88av| 欧美成人金8天国加勒比| 黄色污污污免费在线观看网站| 999久久久精品国产| 亚洲天堂成人在线观看视频网站| 亚洲av综合av一区二区综| 免费黄页网址大全在线观看| 97碰碰碰免费公开在线视频| 国产伦精一区二区三区| 亚洲一区黄色av| 亚洲av超清在线| 精品人妻熟女一区| 日韩av在线免费直播| 国产精品久久久久久av蜜臀| 97视频公开在线观看| 国产精品久久人人添| www.亚洲综合色| 人妻丰满精品一区二区A片| 亚洲av变态另类| 少妇人妻在线一区二区| 久久久久亚洲国产av| 色综合久久综合久久综合网| 丰满熟女少妇午夜福利视频| 婷婷综合五月激情网| 国产在精品在线观看| 午夜精品久久久久久久91蜜桃臀| av男人的东京天堂热| 国产精品,日韩视频| 人妻中文字幕精品| 色婷婷狠狠18禁久久久| 久久免费又粗又长又硬又深又色| 顶级少妇一区二区三区| 偷拍另类激情小说| 欧美日韩亚洲成人一区| 亚洲日产av一区二区在线| 蜜桃视频一区二区精品| 天天综合天天精品| 少妇人妻在线一区二区| 国产夫妻自拍啪啪视频| 91国产av精品| 成人av电影网站日韩| 激情视频在线观看中文字幕| 色婷婷欧美亚洲激情综合另类在线 | av在线免费观看天堂| 伊人五月婷婷激情网| 谁有av网站在线播放中文字幕| 欧美亚洲国产成人在线| 东京热人妻视频在线观看| 久久偷拍美女上厕所| 午夜爽视频在线观看| 人妻一区二区久久中文| 一色桃子av人妻中文字幕| 中村智惠巨乳av| 国产精品毛片久久久久久久久| 蜜桃av噜噜一区二区三区视频| yy8098国产av久久| 免费中文字幕啪啪啪| 日韩欧美中文字幕第一页| 制服丝袜美腿一区二区在线观看| 久久久午夜精品日本| 精品久久久久久久久99| 91精品夜夜夜一区二区三区老板 | 成人av在线天堂一区二区三区| 精品999国内一二三区| 国产熟女啪啪精品一区二区三区| 国产|九色|91| 亚洲av少妇系列| 97久久香蕉国产线看观看 | 亚洲一区二区精品无码99| 久久国产这里只精品免费| 中文人妻精品一区二区三区四区| 91精品在线视频 九色| 日韩 欧美 丝袜| 成人黄色性a大片| 开心网五月天色婷婷| 国产又粗又爽又猛视频| 精品人妻一区二区免费| 国产黑色丝袜在线| 中文字幕人妻xxxx| 91碰碰成人免费视频| 日韩最新视频播放| 色尼玛亚洲综合网| 在线播放一区日韩| 一区二区三区欧美日韩| 亚洲乱熟女一区二区三区在线视频| 欧美激情一级欧美精品| 久久久久久久日本综合| 久久国产精品免费看三级| japanese白嫩人妻hd| 视频一区二区三区免费观看| 国产在线看片免费观看| 国产黄色剧情影片麻豆免费播放| 国产91在线播放小黄鸭| 麻豆精选在线播放视频| 国产av专区网站大全| 亚欧精品视频一区二区三区| 亚洲中文字幕视频免费在线| 亚洲第一页色自拍| 久久久久久一级二级三级| 日韩中文字幕激情在线| 亚洲国产a∨天堂| 激情边亲边摸视频| 日韩国产av大全| 99精品久久久久久久一区| 涩爱av色老久久精品偷偷鲁| 中文字幕成人乱码不卡视频| 加勒比在线视频在线播放| 日本道久久综合久久| 亚洲av成人波多野一区二区| 久久精品视频天天操| 欧美性受xxxx人妻xyv狂| 中国特黄免费大片| 国产久久十八禁一区| 少妇人妻久久久久久久久久| 国产|九色|91| 超碰人妻一区二区三区| 国产自拍偷拍日韩精品| av中文字幕在线播放| 日韩人妻系列在线看| 白嫩丰满少妇大战黑人| 色婷婷a区一区二区三区| 精产国品av一二三产区| 亚洲蜜桃视频在线| 日本大香蕉怡红院| 内射一对幼嫩无毛妹| 青青在线观看视频精品| 午夜av网站观看| 亚洲色影在线视频| 中文字幕日韩精品在线免费| 国产日韩精品成人欧美直接观看 | 99国产小视频在线播放| 中文字幕亚洲自拍偷拍| 久久综合另类激情人妖| 99久re热视频这只有精品6| 丰满女人床上激情久久 | 国产精品久久久久久av蜜臀| 2019中文字幕免费在线观看| 亚洲女人的av天堂| av网站国产在线| 亚洲男人的天堂久久| 亚洲 制服 中文字幕| 国产情侣自拍成人| 久久久久久国产精品av| 美女视频黄免费的亚洲男人天堂| 国产av精品高清| 丝袜人妻精品一区二区三区| 麻豆系列在线播放视频| 天天舔,天天做,天天爽 | 日本老熟妇ⅹxx| 91精品国产综合久蜜臀 | 亚洲一本一道一区二区三区| 日韩av不卡网站| 久久婷婷视频一二三区| 欧美二区三区精品在线| 欧美性欧美视频这里只有| 亚洲中文国产字幕| 国产视频在线观看播放| 亚洲中文字幕日本| 久久精品国产99久久久露| 精彩av在线不卡播放| 国产精品久久久久久av福利| 久久网99精品国产亚洲av| 五月亚洲婷婷亚洲| 国产又粗又长的视频| 999久久精品视频在线| 中国学习在线成人高考| 自拍伦理视频在线观看| 操美女姐姐啊啊啊| 在线中文字幕在线中文| 极品少妇激情av在线| 亚洲久久9999| 99久久精品国产av| 丝袜美腿免费在线| 国产亚洲欧美日韩国产精品三区 | 99精品久久久久久久一区| 91精品夜夜夜一区二区三区老板| yeye38亚洲综合网久久| 天天天天天天天天天天天天天天干| 久久综合日韩欧美| 国产亚洲欧美视频二区| 天天操天天爽天天舔天天射| 国内精品伊人久久久久av网站| 亚洲国产美乳视频| 亚洲无av码一区二区三区| 午夜精品老牛av一区二区三区| 日本五十路熟女网| 凹凸国产熟女白浆精品视频免费| 国产精品久久久久久久久果冻传媒| 久久精品视频在线看15| 日本伦理在线不卡| 亚洲男人的天堂久久| 高清一区二区三区免费| 99国产精品人妻无码一区二区| 国产一区二区精美视频| 99久久久久7777| 草原免费视频亚洲| 日韩毛片短视频在线播放| www国产亚洲精品久久久| 欧美视频亚洲视频在线观看| av天堂中文字幕尤物| 青青草视频 成人| 一级成人黄色影视| 国产又粗又猛又爽无又黄遮拦| av老司机亚洲精品天堂| 精品av综合一区二区三区| 欧美另类极品videoshd| 蜜桃av一区二区精品| 少妇精品久久综合网| 大香蕉伊人免久久| robolox涩涩的视频免费看| 日韩欧美高清一区二区三区| 天天干天天日天天操天天色天天射| 亚洲综合一区在线| 最大的黄色亚洲网站在线观看| 欧美日韩三级在线综合| 日本五十路熟女网| 国产老妇伦国产熟女老妇视频| 国产精品毛片久久久久久久久| 伊人久久大香线蕉综合啪小说| 日韩av在线大片| 国产亚洲欧美视频二区| 午夜三级二区三区| 国产视频一区 在线播放| 国产一区二区三区很黄很爽| 久久免费又粗又长又硬又深又色| 亚洲啊v男人天堂| 五月婷婷色激情网| 国产精品v白虎逼| av在线亚洲最大的| 亚洲自治区二色一区二区三区| 亚洲欧美精品夜色在线网站| 人妻字幕av一区二区三区| 热久久77这里有精品综合久久 | 精品久久久久久久久字幕| 美腿丝袜综合在线日韩| 天天操天天操天天爽| 日日夜夜免费看精品视频| 91色综合综合热五月激情| 好看的av网站中文字幕| 中文字幕不卡一区二区三区| 一本色道久久爱久| 国产精品人妻激情| 国产91熟女高潮一区二区| 26uuu日韩一区二区三区四区| 黑人玩弄人妻一区二一区三区| 免费福利精品视频| 亚洲综合视频麻豆| 青青草国产在线免费观看| 国产日韩高清一区二区| 中文字幕亚洲素人| 日韩精品亚洲性图欧美| 99热这里有国产| 国产精品视频福利在线| 97精品人妻一区二区三区竹菊| 一区二区三区av资源网| 超碰97免费公开在线人妻| 国产99精品久久久久久久| 6666成人在线| 97视频在线播放| 国产精品毛片久久久久久久久| 一级片一级黄色片| 黄色一级片人和兽| 一区二区三区四区五区国产av | 久久午夜一成年人的视频| 熟女av不卡一区| 久操在线免费观看视频| 网页端在线聊天室| 欧美激情一级欧美精品| 最新亚洲国产高清激情| 色哟哟成年人网站| 婷婷综合在线五月天| 色哟哟网站日韩精品| ysl蜜桃色14| 午夜xb福利视频| 日韩美女精品视频| 精品国产露脸久久av| 国产美女啪啪av| 亚洲五月婷婷啪啪| 视频不卡在线观看| 久久精品视频天天操| 亚洲精品在线观看av密乳av| 国产精品视频福利在线| 国产情侣自拍成人| av影音在线不卡| 午夜精品一区二区三区蜜桃| 欧美一区二区三区夫妻| 久草视频在线有精品| 黄色片网站国产精品| 中文字幕av最新更新| 日本女优与黑人特级| 日本老女人性生活视频| 观看国产精品97视频| 亚洲av综合色一区二区三区| 都市激情 校园春色 中文字幕| 久久久久久精品免费免费sss| 人妻一区二区久久中文| 九九七视频在线观看| 亚洲国产高清自拍| 久久精品国产亚洲av麻豆看片| 日韩午夜精品短视频| 在线观看剧情国产| 成人动漫在线观看播放| 一区二区国产中文字幕| 日韩中文有码在线视频| 尤物在线观看视频av| 午夜爽视频在线观看| 天天日天天舔y透| 色在线观看aaa| 四虎日韩在线观看| 99er视频,这里有精品九九| 午夜美女诱惑福利| 丁香激情久久久久伊人精品| 亚洲免费观看女优| 国产一区二区三区自拍欧美| 天天色天天干天天| 国产精品亚洲综合一区在线观看| 波霸肥熟女bbw| 国产精品一区二区三区色| av中文字幕在线播放| 日韩母乳女优激情视频在线观看| 欧美国产精品久久九九| 日韩av不卡在线看| 日韩超碰97在线观看| 国家五a级久久久久久黄片| 日韩av在线1区| 极品视频一区在线观看| 人妻精品中文字幕在线| 久久网99精品国产亚洲av| 人人妻人人爱人人澡| 不卡av中文字幕手机看| 日韩av在线免费直播| 天天操美女综合网| 精品麻豆久久久久久| 久久偷拍美女上厕所| 凹凸视频一二三区在线观看| 91精品老司机视频网站| 精品久久97观看在线ship| 黄色一级成人大片| av在线一区二区三区地区| 亚洲最大黄色福利| 欧美三级韩国三级少妇99| 日韩 午夜 免费| 毛片av福利在线| 亚洲超爽美女毛片| 国产免费理论视频| 中文在线字幕丝袜美腿| 日韩美女深夜网站| 麻豆剧传媒精品国产av| 日韩av手机免费在线观看| 欧美黑人一区二区在线| 久久一区二区三区av| 老熟妇淫老妇女av| 亚洲性色av网站| 亚洲日韩免费视频在线视频| 亚洲中文字幕精品久久app| 日韩av在线1区| 日韩乱码99在线视频| 粉嫩一区二区性色粉嫩av| 久久精品国产露脸对白| 国产免费精品在线播放| 久久久久久精品成人| 五月婷婷综合中文字幕| 国产亚洲精品av成人无删减| 日韩一区不卡二区| 久久国产av人人做人人爽| 久久 91 欧美 精品| 大桥久未无码吹潮在线观看| 婷婷激情网婷婷激情网| 日韩免费观看v.| 亚洲欧洲av天堂| 四虎日韩在线观看| 国产av熟女一区二区三区四季|