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

一篇非常 Nice 的 UmiJS 教程

開發 前端
網上的umi教程是真的少,很多人都只寫了一點點,很多水文,所以打算自己寫一篇,自己搭建umi,并封裝了一下常用的功能,并用到公司實際項目中。

[[437884]]

 前言

網上的umi教程是真的少,很多人都只寫了一點點,很多水文,所以打算自己寫一篇,自己搭建umi,并封裝了一下常用的功能,并用到公司實際項目中.

umi介紹

Umi 是什么?

Umi,中文可發音為烏米,是可擴展的企業級前端應用框架。Umi 以路由為基礎的,同時支持配置式路由和約定式路由,保證路由的功能完備,并以此進行功能擴展。然后配以生命周期完善的插件體系,覆蓋從源碼到構建產物的每個生命周期,支持各種功能擴展和業務需求。

Umi 是螞蟻金服的底層前端框架,已直接或間接地服務了 3000+ 應用,包括 java、node、H5 無線、離線(Hybrid)應用、純前端 assets 應用、CMS 應用等。他已經很好地服務了我們的內部用戶,同時希望他也能服務好外部用戶。

它主要具備以下功能:

  •   🎉 可擴展,Umi 實現了完整的生命周期,并使其插件化,Umi 內部功能也全由插件完成。此外還支持插件和插件集,以滿足功能和垂直域的分層需求。
  •   📦 開箱即用,Umi 內置了路由、構建、部署、測試等,僅需一個依賴即可上手開發。并且還提供針對 React 的集成插件集,內涵豐富的功能,可滿足日常 80% 的開發需求。
  •   🐠 企業級,經螞蟻內部 3000+ 項目以及阿里、優酷、網易、飛豬、口碑等公司項目的驗證,值得信賴。
  •   🚀 大量自研,包含微前端、組件打包、文檔工具、請求庫、hooks 庫、數據流等,滿足日常項目的周邊需求。
  •   🌴 完備路由,同時支持配置式路由和約定式路由,同時保持功能的完備性,比如動態路由、嵌套路由、權限路由等等。
  •   🚄 面向未來,在滿足需求的同時,我們也不會停止對新技術的探索。比如 dll 提速、modern mode、webpack@5、自動化 external、bundler less 等等。

什么時候不用 umi?

如果你,

  •   需要支持 IE 8 或更低版本的瀏覽器
  •   需要支持 React 16.8.0 以下的 React
  •   需要跑在 Node 10 以下的環境中
  •   有很強的 webpack 自定義需求和主觀意愿
  •   需要選擇不同的路由方案

Umi 可能不適合你。

為什么不是?

create-react-app

create-react-app 是基于 webpack 的打包層方案,包含 build、dev、lint 等,他在打包層把體驗做到了極致,但是不包含路由,不是框架,也不支持配置。所以,如果大家想基于他修改部分配置,或者希望在打包層之外也做技術收斂時,就會遇到困難。

next.js

next.js 是個很好的選擇,Umi 很多功能是參考 next.js 做的。要說有哪些地方不如 Umi,我覺得可能是不夠貼近業務,不夠接地氣。比如 antd、dva 的深度整合,比如國際化、權限、數據流、配置式路由、補丁方案、自動化 external 方面等等一線開發者才會遇到的問題。

umi3項目初始化

環境準備

首先得有 node,并確保 node 版本是 10.13 或以上。

推薦使用 yarn 管理 npm 依賴

本項目使用的版本為 node v14.17.5  yarn 1.22.15

腳手架

桌面新建umi3文件夾, 用vscode打開, 打開vscode終端,

執行 yarn create @umijs/umi-app 創建項目

安裝依賴 yarn

啟動項目 yarn start

配置 prettier,eslint, stylelint

umi 維護了一個 prettier,eslint,stylelint 的配置文件合集 umi-fabric 

  1. yarn add @umijs/fabric -D 

根目錄新建下面三個文件,刪除.prettierrc文件

.eslintrc.js、.prettierrc.js、.stylelintrc.js

配置如下 

  1. //.eslintrc.js 配置  
  2. module.exports = {  
  3.   extends: [require.resolve('@umijs/fabric/dist/eslint')],  
  4.   // in antd-design-pro  
  5.   globals: {  
  6.     ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,  
  7.     page: true,  
  8.   }, 
  9.   rules: {  
  10.     // your rules  
  11.     'prefer-const': 0,  
  12.   },  
  13. };  
  14. //.prettierrc.js 配置  
  15. const fabric = require('@umijs/fabric')  
  16. module.exports = {  
  17.   ...fabric.prettier,  
  18.   semi: false,  
  19.  
  20. //.stylelintrc.js 配置  
  21. const fabric = require('@umijs/fabric')  
  22. module.exports = {  
  23.   ...fabric.stylelint,  

根目錄新建eslint忽略文件  .eslintignore 

  1. .eslintrc.js  
  2. node_modules 

在package.json 里面的lint-staged 新增 "eslint --fix"

最后你的 vscode 要安裝這三個同名擴展插件,這時候分別去更改 js、less 文件,會發現已經有風格校驗了。

驗證

修改src/paegs文件夾下的index.tsx文件,新增一個a變量,有eslint錯誤提示,說明eslint生效了

然后再單獨提交index.tsx這一個文件

會提示有錯誤,無法提交,說明pre-commmit 鉤子生效

保存時自動格式化代碼

在vscode設置 文本編輯器的格式化里面  勾選Format on Save

我的eslint,或者prettier 不生效?

去到終端里的輸出,找到eslint或者prettier 看他們的輸出日志,是否正常。如果有報錯,根據報錯信息處理問題

檢查步驟:

  •  確保安裝umi-fabric
  •  檢查配置文件是否存在
  •  vscode 得eslint 和prettier 插件是否下載
  •  確認輸出日志,是否有報錯

pre-commit時的lint-staged 不生效

在package.json中 我們配置了如下得代碼

意思是 在代碼commit之前 執行prettier格式化代碼和eslint fix 如果你在提交代碼的時候沒有生效,請執行

  1. yarn install --force 

執行這個命令重新拉取依賴

不生效的原因?

自己剛開始也是各種google,查看文檔,也沒有找出原因,最后在umi2的一個issue里面,自己找到了答案。

原因在于我們初始化git倉庫的順序,如果我們先初始化git倉庫 然后再創建項目,再拉取依賴。是沒有任何問題的。

如果我們先創建了umi項目,拉去依賴,最后初始化git,提交代碼到git倉庫,當我們拉去依賴時, 這是就還沒有.git 就沒有生成相關的pre-commit,所以就沒有生效。所以這時我們就只需要在重新拉取下依賴就可以了。

配置css初始化代碼

為什么要初始化css

建站老手都知道,這是為了考慮到瀏覽器的兼容問題,其實不同瀏覽器對有些標簽的默認值是不同的,如果沒對CSS初始化往往會出現瀏覽器之間的頁面差異。當然,初始化樣式會對SEO有一定的影響,但魚和熊掌不可兼得,但力求影響最小的情況下初始化。

最簡單的初始化方法就是:* {padding: 0; margin: 0;} 。有很多人也是這樣寫的。這確實很簡單,但有人就會感到疑問:*號這樣一個通用符在編寫代碼的時候是快,但如果網站很大,CSS樣式表文件很大,這樣寫的話,他會把所有的標簽都初始化一遍,這樣就大大的加強了網站運行的負載,會使網站加載的時候需要很長一段時間。

CSS初始化是指重設瀏覽器的樣式。不同的瀏覽器默認的樣式可能不盡相同,所以開發時的第一件事可能就是如何把它們統一。如果沒對CSS初始化往往會出現瀏覽器之間的頁面差異。每次新開發網站或新網頁時候通過初始化CSS樣式的屬性,為我們將用到的CSS或html標簽更加方便準確,使得我們開發網頁內容時更加方便簡潔,同時減少CSS代碼量,節約網頁下載時間。

Umi 中約定 src/global.css 為全局樣式,如果存在此文件,會被自動引入到入口文件最前面。

src下面新建global.css,代碼如下 

  1. body,  
  2. ol,  
  3. ul,  
  4. h1,  
  5. h2,  
  6. h3,  
  7. h4,  
  8. h5,  
  9. h6,  
  10. p,  
  11. th,  
  12. td,  
  13. dl,  
  14. dd,  
  15. form,  
  16. fieldset,  
  17. legend,  
  18. input,  
  19. textarea,  
  20. select,  
  21. figure,  
  22. figcaption {  
  23.   margin: 0;  
  24.   padding: 0;  
  25. li {  
  26.   list-style-type: none;  
  27.  
  28. a {  
  29.   text-decoration: none;  
  30.  
  31. a:hover {  
  32.   text-decoration: underline;  
  33.  
  34. img {  
  35.   border: none;  
  36.  
  37. input {  
  38.   outline: none;  

配置文件

Umi 在 .umirc.ts 或 config/config.ts 中配置項目和插件,支持 es6。

如果項目的配置不復雜,推薦在 .umirc.ts 中寫配置;如果項目的配置比較復雜,可以將配置寫在 config/config.ts 中,并把配置的一部分拆分出去,比如路由配置可以拆分成單獨的 routes.ts

推薦兩種配置方式二選一,.umirc.ts 優先級更高。

我們采用config的方式,刪除.umirc.ts,根目錄新建config文件夾, 在里面新建config.ts

默認內容如下 

  1. import { defineConfig } from 'umi';  
  2. export default defineConfig({ 
  3.   nodeModulesTransform: {  
  4.     type: 'none',  
  5.   },  
  6.   routes: [  
  7.     { path: '/', component: '@/pages/index' },  
  8.   ],  
  9.   fastRefresh: {},  
  10. }); 

多環境多配置文件

可以通過環境變量 UMI_ENV 區分不同環境來指定配置。

為了兼容性,可借助三方工具 cross-env來設置環境變量 

  1. yarn add cross-env --dev 

在package.json中的script中   

  1. "start": "cross-env UMI_ENV=dev umi dev",  
  2.    "start:test": "cross-env UMI_ENV=test umi dev",  
  3.    "start:prd": "cross-env UMI_ENV=prd umi dev",  
  4.    "build": "cross-env UMI_ENV=dev umi build",  
  5.    "build:test": "cross-env UMI_ENV=test umi build",  
  6.    "build:prd": "cross-env UMI_ENV=prd umi build", 

然后再config文件夾下 新建

config.dev.ts,config.test.ts,config.prd.ts

代表開發環境,測試環境,生產環境的配置文件.

config.dev.ts 

  1. import { defineConfig } from 'umi';  
  2. export default defineConfig({ 
  3.   define: {  
  4.     CurrentEnvironment: 'dev',  
  5.   }, 
  6. }); 

config.test.ts 

  1. import { defineConfig } from 'umi';  
  2. export default defineConfig({  
  3.   define: {  
  4.     CurrentEnvironment: 'test',  
  5.   },  
  6. }); 

config.prd.ts 

  1. import { defineConfig } from 'umi';  
  2. export default defineConfig({  
  3.   define: {  
  4.     CurrentEnvironment: 'prd',  
  5.   },  
  6. }); 

CurrentEnvironment 變量代表當前的環境,后面根據不同的環境配置不同的請求地址會用到

用于提供給代碼中可用的變量,定義的變量可以全局拿到

這時 執行 yarn start:prd,然后去到pages的index.tsx打印CurrentEnvironment.

這時需要去到根目錄的 typings.d.ts 添加 

  1. // 聲明當前的環境  
  2. declare const CurrentEnvironment: 'dev' | 'test' | 'prd';  

然后報錯消失 控制臺打印如下

這時 重新執行yanr start:test 控制臺打印如下

環境變量和多環境多配置 成功

**注意點**:

config.ts作為配置文件時,記得刪除.umirc.ts 不然config.ts不會生效。

自定義環境變量

如果我們想自定義一個環境變量,REACT_APP_ENV. 同樣我們可以在package.json里面設置

然后我們要這樣拿到這個變量呢?

首先 我們要在config.ts 的 define 配置 

  1. define: {  
  2.     REACT_APP_ENV: process.env.REACT_APP_ENV,  
  3. }, 

然后再在根目錄的 typings.d.ts 定義

  1. declare const REACT_APP_ENV: string; 

這樣就可以以在全局中拿到和使用 REACT_APP_ENV這個環境變量了.

可以在任意組件 直接打印

  1. console.log('自定義環境變量', REACT_APP_ENV); 

系統自帶的環境變量

官方提供的環境變量

怎么使用?

在根目錄新建.env 環境變量配置文件

然后寫入 

  1. PORT=3000  // 表示啟動的端口號為3000  
  2. COMPRESS = none  // 不壓縮 CSS 和 JS 

還有一些環境變量 不能配在 .env 中,只能在命令行里添加

比如 FORK_TS_CHECKER 默認不開啟 TypeScript 類型檢查,值為 1 時啟用。 

  1. "start": "cross-env FORK_TS_CHECKER=1 UMI_ENV=dev umi dev", 

請求的封裝

src文件夾下新建 request文件夾 新建request.ts

request.ts 

  1. /**  
  2.  * 網絡請求工具 封裝umi-request  
  3.  * 更詳細的 api 文檔: https://github.com/umijs/umi-request  
  4.  */  
  5. import { extend } from 'umi-request';  
  6. import type { RequestOptionsInit } from 'umi-request';  
  7. import { notification } from 'antd';  
  8. // codeMessage僅供參考 具體根據和后端協商,在詳細定義.  
  9. const codeMessage = {  
  10.   200: '服務器成功返回請求的數據。',  
  11.   400: '發出的請求有錯誤,服務器沒有進行新建或修改數據的操作。',  
  12.   500: '服務器發生錯誤,請檢查服務器。',  
  13. };  
  14. type mapCode = 200 | 400 | 500;   
  15. /**  
  16.  * 錯誤異常處理程序  
  17.  */  
  18. const errorHandler = (error: { response: Response }): Response => {  
  19.   const { response } = error;  
  20.   if (response && response.status) {  
  21.     let errorText = codeMessage[response.status as mapCode] || response.statusText;  
  22.     const { status, url } = response;  
  23.     response  
  24.       ?.clone()  
  25.       ?.json()  
  26.       ?.then((res) => {  
  27.         // 后端返回錯誤信息,就用后端傳回的  
  28.         errorText = res.msg ? res.msg : errorText;  
  29.         notification.error({  
  30.           message: `請求錯誤 ${status}: ${url}`,  
  31.           description: errorText,  
  32.         });  
  33.       });  
  34.   } else if (!response) {  
  35.     notification.error({  
  36.       description: '您的網絡發生異常,無法連接服務器', 
  37.       message: '網絡異常',  
  38.     });  
  39.   }  
  40.   return response;  
  41. };  
  42. /**  
  43.  * 配置request請求時的默認參數  
  44.  */  
  45. const request = extend({  
  46.   errorHandler, // 默認錯誤處理  
  47.   credentials: 'include', // 默認請求是否帶上cookie  
  48. });  
  49. // 根據不同的開發環境,配置請求前綴  
  50. interface ApiPrefix {  
  51.   dev: string;  
  52.   test: string;  
  53.   prd: string;  
  54.  
  55. const apiPreFix: ApiPrefix = {  
  56.   dev: 'http://120.55.193.14:3030/',  
  57.   test: 'http://120.55.193.14:3030/',  
  58.   prd: 'http://120.55.193.14:3030/',  
  59. };  
  60. // request攔截器, 攜帶token,以及根據環境,配置不同的請求前綴  
  61. request.interceptors.request.use((url: string, options: RequestOptionsInit) => {  
  62.   // 不攜帶token的請求數組  
  63.   let notCarryTokenArr: string[] = [];  
  64.   if (notCarryTokenArr.includes(url)) {  
  65.     return {  
  66.       url: `${apiPreFix[CurrentEnvironment]}${url}`,  
  67.       options,  
  68.     };  
  69.   }  
  70.   // 給每個請求帶上token  
  71.   let token = localStorage.getItem('tokens') || '';  
  72.   let headers = {  
  73.     Authorization: `Bearer ${token}`,  
  74.   };  
  75.   return {  
  76.     url: `${apiPreFix[CurrentEnvironment]}${url}`,  
  77.     options: { ...options, interceptors: true, headers },  
  78.   };  
  79. });  
  80. /**  
  81.  * @url 請求的url  
  82.  * @parameter 上傳的參數  
  83.  */  
  84. // 封裝的get,post.put,delete請求  
  85. const get = async (url: string, parameter?: Record<string, unknown>): Promise<any> => {  
  86.   try { 
  87.     const res = await request(url, { method: 'get', params: parameter });  
  88.     return res;  
  89.   } catch (error) {  
  90.     console.error(error);  
  91.   }  
  92. };  
  93. const deletes = async (url: string, parameter?: Record<string, unknown>): Promise<any> => {  
  94.   try {  
  95.     const res = await request(url, { method: 'delete', params: parameter });  
  96.     return res;  
  97.   } catch (error) {  
  98.     console.error(error);  
  99.   }  
  100. };  
  101. const post = async (url: string, parameter?: Record<string, unknown>): Promise<any> => {  
  102.   try {  
  103.     const res = await request(url, { method: 'post', data: parameter });  
  104.     return res;  
  105.   } catch (error) {  
  106.     console.error(error);  
  107.   }  
  108. };  
  109. const put = async (url: string, parameter?: Record<string, unknown>): Promise<any> => {  
  110.   try {  
  111.     const res = await request(url, { method: 'put', data: parameter });  
  112.     return res;  
  113.   } catch (error) {  
  114.     console.error(error);  
  115.   }  
  116. };  
  117. export default {  
  118.   get,  
  119.   post,  
  120.   put,  
  121.   deletes,  
  122. }; 

這里封裝了umi-request,統一處理了接口錯誤,請求攔截器攜帶token等.最后在配合useRequest 非常的好用.

umi中使用dva

介紹

包含以下功能,

  •  內置 dva,默認版本是 ^2.6.0-beta.20,如果項目中有依賴,會優先使用項目中依賴的版本。
  •  約定式的 model 組織方式,不用手動注冊 model
  •  文件名即 namespace,model 內如果沒有聲明 namespace,會以文件名作為 namespace
  •  內置 dva-loading,直接 connect loading 字段使用即可
  •  支持 immer,通過配置 immer 開啟

約定式的 model 組織方式

符合以下規則的文件會被認為是 model 文件,

  •  src/models 下的文件
  •  src/pages 下,子目錄中 models 目錄下的文件
  •  src/pages 下,所有 model.ts 文件(不區分任何字母大小寫)

實際使用

比如在src下新建 models文件夾,里面新建test.ts

test.ts 

  1. import type { Effect, Reducer, Subscription } from 'umi'; // 映入umi 定義好的ts類型  
  2. import axios from '../request/request'; // 引入封裝好的網絡請求  
  3. // state 接口  
  4. export interface TextModelState { 
  5.   name?: string;  
  6.   testData?: string;  
  7. // test model接口  
  8. export interface TextModelType {  
  9.   namespace: 'testModel';  
  10.   state: TextModelState;  
  11.   effects: {  
  12.     query: Effect;  
  13.   };  
  14.   reducers: {  
  15.     save: Reducer<TextModelState> 
  16.     msg: Reducer<TextModelState> 
  17.   };  
  18.   subscriptions?: { setup: Subscription };  
  19.  
  20. const IndexModel: TextModelType = {  
  21.   namespace: 'testModel',  
  22.   state: {  
  23.     name: '初始名字',  
  24.     testData: '初始testData',  
  25.   },  
  26.   effects: {  
  27.     *query(action, { call, put }) {  
  28.       const getDataTest = async () => {  
  29.         const data = await axios.get('test'); 
  30.         return data;  
  31.       };  
  32.       let testData = yield call(getDataTest); 
  33.       yield put({  
  34.         type: 'msg',  
  35.         data: { testData: testData?.msg },  
  36.       });  
  37.     },  
  38.   },  
  39.   reducers: {  
  40.     save(state) {  
  41.       return {  
  42.         ...state,  
  43.         name: 'jimmy',  
  44.       };  
  45.     },  
  46.     msg(state, action) {  
  47.       return {  
  48.         ...state,  
  49.         testData: action?.data?.testData,  
  50.         testData2: action?.data?.testData2,  
  51.       };  
  52.     },  
  53.   },  
  54. };  
  55. export default IndexModel; 

在src/pages下的index.tsx中使用

index.tsx 

  1. import type { Effect, Reducer, Subscription } from 'umi'; // 引入umi 定義好的ts類型  
  2. import axios from '../request/request'; // 引入封裝好的網絡請求  
  3. // state 接口  
  4. export interface TextModelState {  
  5.   name?: string;  
  6.   testData?: string;  
  7.  
  8. // test model接口  
  9. export interface TextModelType {  
  10.   namespace: 'testModel';  
  11.   state: TextModelState;  
  12.   effects: {  
  13.     query: Effect;  
  14.   };  
  15.   reducers: {  
  16.     save: Reducer<TextModelState> 
  17.     msg: Reducer<TextModelState> 
  18.   };  
  19.   subscriptions?: { setup: Subscription };  
  20.  
  21. const IndexModel: TextModelType = {  
  22.   namespace: 'testModel',  
  23.   state: {  
  24.     name: '初始名字',  
  25.     testData: '初始testData',  
  26.   },  
  27.   effects: {  
  28.     *query(action, { call, put }) {  
  29.       const getDataTest = async () => {  
  30.         const data = await axios.get('test');  
  31.         return data;  
  32.       };  
  33.       let testData = yield call(getDataTest); 
  34.       yield put({  
  35.         type: 'msg',  
  36.         data: { testData: testData?.msg },  
  37.       });  
  38.     },  
  39.   },  
  40.   reducers: {  
  41.     save(state) {  
  42.       return {  
  43.         ...state,  
  44.         name: 'jimmy',  
  45.       };  
  46.     },  
  47.     msg(state, action) {  
  48.       return {  
  49.         ...state,  
  50.         testData: action?.data?.testData,  
  51.         testData2: action?.data?.testData2,  
  52.       };  
  53.     },  
  54.   },  
  55. };  
  56. export default IndexModel; 

mfsu

啟用 mfsu 后,熱啟動得到 **10 倍** 提升;熱更新提升 **50%** 以上!

如何啟用

在 config/config.ts 中添加 mfsu:{}

項目源代碼

請點擊我

和兩個小伙伴一起,會根據實際運用中出現的問題或者沒有考慮完善的地方,持續的更新迭代.如有問題,歡迎提Issue或者在評論區留言

FAQ

umi 不是內部或外部命令

解決辦法

執行 yarn global bin 拿到 bin 路徑。然后把這個路徑添加到環境變量里面的系統變量的path里面

如果還是不行,執行 

  1. yarn global add umi 

如遇到更多問題,請查考

官方FAQ

官方倉庫的issue 

 

責任編輯:龐桂玉 來源: 前端大全
相關推薦

2022-07-06 07:57:37

Zookeeper分布式服務框架

2018-11-01 13:20:05

Python爬蟲編程語言

2020-01-13 13:10:29

技術研發運維

2021-05-11 09:31:31

kustomizeoperator kubernetes

2021-05-08 09:02:48

KubeBuilderOperatork8s

2021-09-18 07:43:33

ApolloJava配置中心

2021-10-14 09:58:24

消息中間件ActiveMQ Java

2021-09-15 19:05:16

數據開源項目

2021-07-12 06:11:14

SkyWalking 儀表板UI篇

2022-10-26 07:39:36

MVCC數據庫RR

2022-12-19 08:14:30

注解開發配置

2022-01-02 08:43:46

Python

2021-08-01 07:19:16

語言OpenrestyNginx

2022-06-30 22:53:18

數據結構算法

2021-08-11 07:02:21

npm包管理器工具

2021-05-20 06:57:16

RabbitMQ開源消息

2022-02-07 11:01:23

ZooKeeper

2023-04-20 08:00:00

ES搜索引擎MySQL

2023-10-30 07:12:04

2021-10-26 10:40:26

代理模式虛擬
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 毛片1| www.一区二区三区.com | 久久久99精品免费观看 | 久久久999成人 | 国产精品久久久久久久午夜片 | 黄视频欧美 | jav成人av免费播放 | 在线国产一区 | 精品国产一区一区二区三亚瑟 | 在线免费中文字幕 | 国产精品一区二区在线播放 | 国产欧美一区二区久久性色99 | 精品国产乱码久久久久久影片 | 国产成人av在线播放 | 黄在线免费观看 | 综合五月婷| 黄免费观看 | 黄色毛片在线看 | 91视频正在播放 | 欧美福利影院 | 男女在线网站 | 国产不卡一区在线观看 | 久久精品国产免费看久久精品 | 国产美女在线观看 | 亚洲毛片在线观看 | 国产成人免费一区二区60岁 | 欧美色欧美亚洲另类七区 | 日韩免费网站 | 成人免费三级电影 | 国产精品人人做人人爽 | 先锋av资源网 | 91精品国产综合久久婷婷香蕉 | 久久黄色网| 精品九九 | 久久精品小短片 | 国产一区二区在线播放 | 欧美人成在线视频 | 亚洲最大的黄色网址 | 国产日韩一区 | 激情在线视频 | 中文字幕 在线观看 |