91精彩视频在线观看_国产强伦姧在线观看无码_欧美国产日韩综合在线_国产精品莉莉欧美自在线线

歡迎來到深圳市來科信科技有限公司網站!

已閱讀

基于Vue和TS的Web移動端發開項目實戰心得

來源:m.bqtao.cn ?? ?? 發布時間:2019-09-27
筆者在公司用 web 技術開發移動端應用已經有一年多的時間了,開始主要以 vue 技術棧配合 native 為主,目前演進成 vue + react native 技術架構,vue 主要負責開發 OA 業務,比如報銷、出差、crm 等等,react native 主要負責即時通信部分,是在 mattermost-mobile[1] 的基礎上修改的(mattermost 是一個開源的即時通訊方案)。

因為公司在這方面沒有太多技術沉淀,所以在開發期間遇到了很多坑,經過一年多的技術攻克積累,最終形成了這套比較完善的解決方案,總結出來希望能夠幫助到大家,尤其是對一些中小公司這方面經驗不足的(PS: 大公司估計有他們自己的一套方案了)。

好了廢話不多說,先亮下這個庫的 GitHub 地址,后面還會不斷完善,歡迎 star:

mobile-web-best-practice[2]

移動端 web 最佳實踐,基于 vue-cli3[3] 搭建的 typescript[4] 項目,可以用于 hybrid 應用或者純 webapp 開發。以下大部分內容同樣適用于 react[5] 等前端框架。

其中有三個點尚在完善中:領域驅動設計(DDD)應用、微前端、性能監控,后續完成后會以單獨的文章發出來。其中性能監控還沒有太好的選擇,類似錯誤監控 sentry 那種開源免費而且功能強大的工具,如果有人知道的麻煩告知下。文中難免有些錯誤或者更好的方案,也歡迎不吝賜教。

目錄

  • 組件庫[6]

  • JSBridge[7]

  • 路由堆棧管理(模擬原生 APP 導航)[8]

  • 請求數據緩存[9]

  • 構建時預渲染[10]

  • Webpack 策略[11]

    • 基礎庫抽離[12]

  • 手勢庫[13]

  • 樣式適配[14]

  • 表單校驗[15]

  • 阻止原生返回事件[16]

  • 通過 UA 獲取設備信息[17]

  • mock 數據[18]

  • 調試控制臺[19]

  • 抓包工具[20]

  • 異常監控平臺[21]

  • 常見問題[22]

組件庫

vant[23]

vux[24]

mint-ui[25]

cube-ui[26]

vue 移動端組件庫目前主要就是上面羅列的這幾個庫,本項目使用的是有贊前端團隊開源的 vant。

vant 官方目前已經支持自定義樣式主題,基本原理就是在 less-loader[27] 編譯 less[28] 文件到 css 文件過程中,利用 less 提供的 modifyVars[29] 對 less 變量進行修改,本項目也采用了該方式,具體配置請查看相關文檔:

定制主題[30]

推薦一篇介紹各個組件庫特點的文章:

Vue 常用組件庫的比較分析(移動端)[31]

JSBridge

DSBridge-IOS[32]

DSBridge-Android[33]

WebViewJavascriptBridge[34]

混合應用中一般都是通過 webview 加載網頁,而當網頁要獲取設備能力(例如調用攝像頭、本地日歷等)或者 native 需要調用網頁里的方法,就需要通過 JSBridge 進行通信。

開源社區中有很多功能強大的 JSBridge,例如上面列舉的庫。本項目基于保持 iOS android 平臺接口統一原因,采用了 DSBridge,各位可以選擇適合自己項目的工具。

本項目以 h5 調用 native 提供的同步日歷接口為例,演示如何在 dsbridge 基礎上進行兩端通信的。下面是兩端的關鍵代碼摘要:

安卓端同步日歷核心代碼,具體代碼請查看與本項目配套的安卓項目 mobile-web-best-practice-container[35]

public class JsApi {
    /**
     * 同步日歷接口
     * msg 格式如下:
     * ...
     */
    @JavascriptInterface
    public void syncCalendar(Object msg, CompletionHandler handler) {
        try {
            JSONObject obj = new JSONObject(msg.toString());
            String id = obj.getString("id");
            String title = obj.getString("title");
            String location = obj.getString("location");
            long startTime = obj.getLong("startTime");
            long endTime = obj.getLong("endTime");
            JSONArray earlyRemindTime = obj.getJSONArray("alarm");
            String res = CalendarReminderUtils.addCalendarEvent(id, title, location, startTime, endTime, earlyRemindTime);
            handler.complete(Integer.valueOf(res));
        } catch (Exception e) {
            e.printStackTrace();
            handler.complete(6005);
        }
    }
}

h5 端同步日歷核心代碼(通過裝飾器來限制調用接口的平臺)

class NativeMethods {
  // 同步到日歷
  @p()
  public syncCalendar(params: SyncCalendarParams) {
    const cb = (errCode: number) => {
      const msg = NATIVE_ERROR_CODE_MAP[errCode];

      Vue.prototype.$toast(msg);

      if (errCode !== 6000) {
        this.errorReport(msg, 'syncCalendar', params);
      }
    };
    dsbridge.call('syncCalendar', params, cb);
  }

  // 調用 native 接口出錯向 sentry 發送錯誤信息
  private errorReport(errorMsg: string, methodName: string, params: any) {
    if (window.$sentry) {
      const errorInfo: NativeApiErrorInfo = {
        error: new Error(errorMsg),
        type: 'callNative',
        methodName,
        params: JSON.stringify(params)
      };
      window.$sentry.log(errorInfo);
    }
  }
}

/**
 * @param {platforms} - 接口限制的平臺
 * @return {Function} - 裝飾器
 */
function p(platforms = ['android', 'ios']) {
  return (target: AnyObject, name: string, descriptor: PropertyDescriptor) => {
    if (!platforms.includes(window.$platform)) {
      descriptor.value = () => {
        return Vue.prototype.$toast(
          `當前處在 ${window.$platform} 環境,無法調用接口哦`
        );
      };
    }

    return descriptor;
  };
}

另外推薦一個筆者之前寫的一個基于安卓平臺實現的教學版 JSBridge[36],里面詳細闡述了如何基于底層接口一步步封裝一個可用的 JSBridge:

JSBridge 實現原理[37]

路由堆棧管理(模擬原生 APP 導航)

vue-page-stack[38]

vue-navigation[39]

vue-stack-router[40]

在使用 h5 開發 app,會經常遇到下面的需求:從列表進入詳情頁,返回后能夠記住當前位置,或者從表單點擊某項進入到其他頁面選擇,然后回到表單頁,需要記住之前表單填寫的數據。可是目前 vue 或 react 框架的路由,均不支持同時存在兩個頁面實例,所以需要路由堆棧進行管理。

其中 vue-page-stack 和 vue-navigation 均受 vue 的 keepalive 啟發,基于 vue-router[41],當進入某個頁面時,會查看當前頁面是否有緩存,有緩存的話就取出緩存,并且清除排在他后面的所有 vnode,沒有緩存就是新的頁面,需要存儲或者是 replace 當前頁面,向棧里面 push 對應的 vnode,從而實現記住頁面狀態的功能。

而邏輯思維前端團隊的 vue-stack-router 則另辟蹊徑,拋開了 vue-router,自己獨立實現了路由管理,相較于 vue-router,主要是支持同時可以存活 A 和 B 兩個頁面的實例,或者 A 頁面不同狀態的兩個實例,并支持原生左滑功能。但由于項目還在初期完善,功能還沒有 vue-router 強大,建議持續關注后續動態再做決定是否引入。

本項目使用的是 vue-page-stack,各位可以選擇適合自己項目的工具。同時推薦幾篇相關文章:

【vue-page-stack】Vue 單頁應用導航管理器 正式發布[42]

Vue 社區的路由解決方案:vue-stack-router[43]

請求數據緩存

mem[44]

在我們的應用中,會存在一些很少改動的數據,而這些數據有需要從后端獲取,比如公司人員、公司職位分類等,此類數據在很長一段時間時不會改變的,而每次打開頁面或切換頁面時,就重新向后端請求。為了能夠減少不必要請求,加快頁面渲染速度,可以引用 mem 緩存庫。

mem 基本原理是通過以接收的函數為 key 創建一個 WeakMap,然后再以函數參數為 key 創建一個 Map,value 就是函數的執行結果,同時將這個 Map 作為剛剛的 WeakMap 的 value 形成嵌套關系,從而實現對同一個函數不同參數進行緩存。而且支持傳入 maxAge,即數據的有效期,當某個數據到達有效期后,會自動銷毀,避免內存泄漏。

選擇 WeakMap 是因為其相對 Map 保持對鍵名所引用的對象是弱引用,即垃圾回收機制不將該引用考慮在內。只要所引用的對象的其他引用都被清除,垃圾回收機制就會釋放該對象所占用的內存。也就是說,一旦不再需要,WeakMap 里面的鍵名對象和所對應的鍵值對會自動消失,不用手動刪除引用。

mem 作為高階函數,可以直接接受封裝好的接口請求。但是為了更加直觀簡便,我們可以按照類的形式集成我們的接口函數,然后就可以用裝飾器的方式使用 mem 了(裝飾器只能修飾類和類的類的方法,因為普通函數會存在變量提升)。下面是相關代碼:

import http from '../http';
import mem from 'mem';

/**
 * @param {MemOption} - mem 配置項
 * @return {Function} - 裝飾器
 */
export default function m(options: AnyObject) {
  return (target: AnyObject, name: string, descriptor: PropertyDescriptor) => {
    const oldValue = descriptor.value;
    descriptor.value = mem(oldValue, options);
    return descriptor;
  };
}

class Home {
  @m({ maxAge: 60 * 1000 })
  public async getUnderlingDailyList(
    query: ListQuery
  ): Promise<{ total: number; list: DailyItem[] }> {
    const {
      data: { total, list }
    } = await http({
      method: 'post',
      url: '/daily/getList',
      data: query
    });

    return { total, list };
  }
}

export default new Home();

 

構建時預渲染

針對目前單頁面首屏渲染時間長(需要下載解析 js 文件然后渲染元素并掛載到 id 為 app 的 div 上),SEO 不友好(index.html 的 body 上實際元素只有 id 為 app 的 div 元素,真正的頁面元素都是動態掛載的,搜索引擎的爬蟲無法捕捉到),目前主流解決方案就是服務端渲染(SSR),即從服務端生成組裝好的完整靜態 html 發送到瀏覽器進行展示,但配置較為復雜,一般都會借助框架,比如 vue 的 nuxt.js[45],react 的 next[46]

其實有一種更簡便的方式--構建時預渲染。顧名思義,就是項目打包構建完成后,啟動一個 Web Server 來運行整個網站,再開啟多個無頭瀏覽器(例如 Puppeteer[47]Phantomjs[48] 等無頭瀏覽器技術)去請求項目中所有的路由,當請求的網頁渲染到第一個需要預渲染的頁面時(需提前配置需要預渲染頁面的路由),會主動拋出一個事件,該事件由無頭瀏覽器截獲,然后將此時的頁面內容生成一個 HTML(包含了 JS 生成的 DOM 結構和 CSS 樣式),保存到打包文件夾中。

根據上面的描述,我們可以其實它本質上就只是快照頁面,不適合過度依賴后端接口的動態頁面,比較適合變化不頻繁的靜態頁面。

實際項目相關工具方面比較推薦 prerender-spa-plugin[49] 這個 webpack 插件,下面是這個插件的原理圖。不過有兩點需要注意:

一個是這個插件需要依賴 Puppeteer,而因為國內網絡原因以及本身體積較大,經常下載失敗,不過可以通過 .npmrc 文件指定 Puppeteer 的下載路徑為國內鏡像;

另一個是需要設置路由模式為 history 模式(即基于 html5 提供的 history api 實現的,react 叫 BrowserRouter,vue 叫 history),因為 hash 路由無法對應到實際的物理路由。(即線上渲染時 history 下,如果 form 路由被設置成預渲染,那么訪問 /form/ 路由時,會直接從服務端返回 form 文件夾下的 index.html,之前打包時就已經預先生成了完整的 HTML 文件 )

本項目已經集成了 prerender-spa-plugin,但由于和 vue-stack-page/vue-navigation 這類路由堆棧管理器一起使用有問題(原因還在查找,如果知道的朋友也可以告知下),所以 prerender 功能是關閉的。

同時推薦幾篇相關文章:

vue 預渲染之 prerender-spa-plugin 解析(一)[50]

使用預渲提升 SPA 應用體驗[51]

Webpack 策略

基礎庫抽離

對于一些基礎庫,例如 vue、moment 等,屬于不經常變化的靜態依賴,一般需要抽離出來以提升每次構建的效率。目前主流方案有兩種:

一種是使用 webpack-dll-plugin[52] 插件,在首次構建時就講這些靜態依賴單獨打包,后續只需引入早已打包好的靜態依賴包即可;

另一種就是外部擴展 Externals[53] 方式,即把不需要打包的靜態資源從構建中剔除,使用 CDN 方式引入。下面是 webpack-dll-plugin 相對 Externals 的缺點:

  1. 需要配置在每次構建時都不參與編譯的靜態依賴,并在首次構建時為它們預編譯出一份 JS 文件(后文將稱其為 lib 文件),每次更新依賴需要手動進行維護,一旦增刪依賴或者變更資源版本忘記更新,就會出現 Error 或者版本錯誤。

  2. 無法接入瀏覽器的新特性 script type="module",對于某些依賴庫提供的原生 ES Modules 的引入方式(比如 vue 的新版引入方式)無法得到支持,沒法更好地適配高版本瀏覽器提供的優良特性以實現更好地性能優化。

  3. 將所有資源預編譯成一份文件,并將這份文件顯式注入項目構建的 HTML 模板中,這樣的做法,在 HTTP1 時代是被推崇的,因為那樣能減少資源的請求數量,但在 HTTP2 時代如果拆成多個 CDN Link,就能夠更充分地利用 HTTP2 的多路復用特性。

不過選擇 Externals 還是需要一個靠譜的 CDN 服務的。

本項目選擇的是 Externals,各位可根據項目需求選擇不同的方案。

更多內容請查看這篇文章(上面觀點來自于這篇文章):

Webpack 優化——將你的構建效率提速翻倍[54]

手勢庫

hammer.js[55]

AlloyFinger[56]

在移動端開發中,一般都需要支持一些手勢,例如拖動(Pan),縮放(Pinch),旋轉(Rotate),滑動(swipe)等。目前已經有很成熟的方案了,例如 hammer.js 和騰訊前端團隊開發的 AlloyFinger 都很不錯。本項目選擇基于 hammer.js 進行二次封裝成 vue 指令集,各位可根據項目需求選擇不同的方案。

下面是二次封裝的關鍵代碼,其中用到了 webpack 的 require.context 函數來獲取特定模塊的上下文,主要用來實現自動化導入模塊,比較適用于像 vue 指令這種模塊較多的場景:

// 用于導入模塊的上下文
export const importAll = (
  context: __WebpackModuleApi.RequireContext,
  options: ImportAllOptions = {}
): AnyObject => {
  const { useDefault = true, keyTransformFunc, filterFunc } = options;

  let keys = context.keys();

  if (isFunction(filterFunc)) {
    keys = keys.filter(filterFunc);
  }

  return keys.reduce((acc: AnyObject, curr: string) => {
    const key = isFunction(keyTransformFunc) ? keyTransformFunc(curr) : curr;
    acc[key] = useDefault ? context(curr).default : context(curr);
    return acc;
  }, {});
};

// directives 文件夾下的 index.ts
const directvieContext = require.context('./', false, /.ts$/);
const directives = importAll(directvieContext, {
  filterFunc: (key: string) => key !== './index.ts',
  keyTransformFunc: (key: string) =>
    key.replace(/^.//, '').replace(/.ts$/, '')
});

export default {
  install(vue: typeof Vue): void {
    Object.keys(directives).forEach((key) =>
      vue.directive(key, directives[key])
    );
  }
};

// touch.ts
export default {
  bind(el: HTMLElement, binding: DirectiveBinding) {
    const hammer: HammerManager = new Hammer(el);
    const touch = binding.arg as Touch;
    const listener = binding.value as HammerListener;
    const modifiers = Object.keys(binding.modifiers);

    switch (touch) {
      case Touch.Pan:
        const panEvent = detectPanEvent(modifiers);
        hammer.on(`pan${panEvent}`, listener);
        break;
      ...
    }
  }
};

另外推薦一篇關于 hammer.js 和一篇關于 require.context 的文章:

H5 案例分享:JS 手勢框架 —— Hammer.js[57]

使用 require.context 實現前端工程自動化[58]

樣式適配

postcss-px-to-viewport[59]

Viewport Units Buggyfill[60]

flexible[61]

postcss-pxtorem[62]

Autoprefixer[63]

browserslist[64]

在移動端網頁開發時,樣式適配始終是一個繞不開的問題。對此目前主流方案有 vw 和 rem(當然還有 vw + rem 結合方案,請見下方 rem-vw-layout 倉庫),其實基本原理都是相通的,就是隨著屏幕寬度或字體大小成正比變化。因為原理方面的詳細資料網絡上已經有很多了,就不在這里贅述了。下面主要提供一些這工程方面的工具。

關于 rem,阿里無線前端團隊在 15 年的時候基于 rem 推出了 flexible 方案,以及 postcss 提供的自動轉換 px 到 rem 的插件 postcss-pxtorem。

關于 vw,可以使用 postcss-px-to-viewport 進行自動轉換 px 到 vw。postcss-px-to-viewport 相關配置如下:

"postcss-px-to-viewport": {
  viewportWidth: 375, // 視窗的寬度,對應的是我們設計稿的寬度,一般是375
  viewportHeight: 667, // 視窗的高度,根據750設備的寬度來指定,一般指定1334,也可以不配置
  unitPrecision: 3,  // 指定`px`轉換為視窗單位值的小數位數(很多時候無法整除)
  viewportUnit: 'vw', // 指定需要轉換成的視窗單位,建議使用vw
  selectorBlackList: ['.ignore', '.hairlines'], // 指定不轉換為視窗單位的類,可以自定義,可以無限添加,建議定義一至兩個通用的類名
  minPixelValue: 1, // 小于或等于`1px`不轉換為視窗單位,你也可以設置為你想要的值
  mediaQuery: false // 媒體查詢里的單位是否需要轉換單位
}

下面是 vw 和 rem 的優缺點對比圖:

關于 vw 兼容性問題,目前在移動端 iOS 8 以上以及 Android 4.4 以上獲得支持。如果有兼容更低版本需求的話,可以選擇 viewport 的 pollify 方案,其中比較主流的是 Viewport Units Buggyfill[65]。

本方案因不準備兼容低版本,所以直接選擇了 vw 方案,各位可根據項目需求選擇不同的方案。

另外關于設置 css 兼容不同瀏覽器,想必大家都知道 Autoprefixer(vue-cli3 已經默認集成了),那么如何設置要兼容的范圍呢?推薦使用 browserslist,可以在 .browserslistrc 或者 pacakage.json 中 browserslist 部分設置兼容瀏覽器范圍。因為不止 Autoprefixer,還有 Babel,postcss-preset-env 等工具都會讀取 browserslist 的兼容配置,這樣比較容易使 js css 兼容瀏覽器的范圍保持一致。下面是本項目的 .browserslistrc 配置:

iOS >= 10  //  即 iOS Safari
Android >= 6.0 // 即 Android WebView
last 2 versions // 每個瀏覽器最近的兩個版本

最后推薦一些移動端樣式適配的資料:

rem-vw-layout[66]

細說移動端 經典的 REM 布局 與 新秀 VW 布局[67]

如何在 Vue 項目中使用 vw 實現移動端適配[68]

表單校驗

async-validator[69]

vee-validate[70]

由于大部分移動端組件庫都不提供表單校驗,因此需要自己封裝。目前比較多的方式就是基于 async-validator 進行二次封裝(elementUI 組件庫提供的表單校驗也是基于 async-validator ),或者使用 vee-validate(一種基于 vue 模板的輕量級校驗框架)進行校驗,各位可根據項目需求選擇不同的方案。

本項目的表單校驗方案是在 async-validator 基礎上進行二次封裝,代碼如下,原理很簡單,基本滿足需求。如果還有更完善的方案,歡迎提出來。

其中 setRules 方法是將組件中設置的 rules(符合 async-validator 約定的校驗規則)按照需要校驗的數據的名字為 key 轉化一個對象 validator,value 是 async-validator 生成的實例。validator 方法可以接收單個或多個需要校驗的數據的 key,然后就會在 setRules 生成的對象 validator 中尋找 key 對應的 async-validator 實例,最后調用實例的校驗方法。當然也可以不接受參數,那么就會校驗所有傳入的數據。

import schema from 'async-validator';
...

class ValidatorUtils {
  private data: AnyObject;
  private validators: AnyObject;

  constructor({ rules = {}, data = {}, cover = true }) {
    this.validators = {};
    this.data = data;
    this.setRules(rules, cover);
  }

  /**
   * 設置校驗規則
   * @param rules async-validator 的校驗規則
   * @param cover 是否替換舊規則
   */
  public setRules(rules: ValidateRules, cover: boolean) {
    if (cover) {
      this.validators = {};
    }

    Object.keys(rules).forEach((key) => {
      this.validators[key] = new schema({ [key]: rules[key] });
    });
  }

  public validate(
    dataKey?: string | string[]
  ): Promisestring | string[] | undefined> {
    // 錯誤數組
    const err: ValidateError[] = [];

    Object.keys(this.validators)
      .filter((key) => {
        // 若不傳 dataKey 則校驗全部。否則校驗 dataKey 對應的數據(dataKey 可以對應一個(字符串)或多個(數組))
        return (
          !dataKey ||
          (dataKey &&
            ((_.isString(dataKey) && dataKey === key) ||
              (_.isArray(dataKey) && dataKey.includes(key))))
        );
      })
      .forEach((key) => {
        this.validators[key].validate(
          { [key]: this.data[key] },
          (error: ValidateError[]) => {
            if (error) {
              err.push(error[0]);
            }
          }
        );
      });

    if (err.length > 0) {
      return Promise.reject(err);
    } else {
      return Promise.resolve(dataKey);
    }
  }
}

阻止原生返回事件

開發中可能會遇到下面這個需求:當頁面彈出一個 popup 或 dialog 組件時,點擊返回鍵時是隱藏彈出的組件而不是返回到上一個頁面。

為了解決這個問題,我們可以從路由棧角度思考。一般彈出組件是不會在路由棧上添加任何記錄,因此我們在彈出組件時,可以在路由棧中 push 一個記錄,為了不讓頁面跳轉,我們可以把跳轉的目標路由設置為當前頁面路由,并加上一個 query 來標記這個組件彈出的狀態。

然后監聽 query 的變化,當點擊彈出組件時,query 中與該彈出組件有關的標記變為 true,則將彈出組件設為顯示;當用戶點擊 native 返回鍵時,路由返回上一個記錄,仍然是當前頁面路由,不過 query 中與該彈出組件有關的標記不再是 true 了,這樣我們就可以把彈出組件設置成隱藏,同時不會返回上一個頁面。

APP開發 網站開發 產品設計 微信公眾號 APP開發公司 用戶體驗 APP運營 微信小程序 產品經理 網站設計
主站蜘蛛池模板: 久久一线| 99精品视频99| 日韩不卡高清| 色姑娘av| 亚洲av无码国产综合专区| 玖玖在线| 久久精品亚洲精品| 中文日韩在线| 1级片在线观看| 国产精品自拍网站| 国产精品乱| 日韩中文字幕国产| 先锋影音男人| 丰满人妻一区二区| 爱爱一区二区三区| 在线视频网站| 婷婷在线免费观看| 亚洲一区免费在线观看| 亚洲乱妇| 内射后入在线观看一区| 就要干就要操| 欧美成人综合视频| 台湾a级艳片潘金莲| 成人aaa| 蜜桃久久av一区| wwwxxx黄色| 久久久久久久久艹| 奇米影| 黄色小说在线看| 富二代成人短视频| 香蕉毛片| 国产按摩一区二区三区| 欧美在线观看一区| 热热色国产| 欧美夫妻性生活视频| 激情五月婷婷在线| 东京热一区二区三区四区| 天天操夜夜干| 黄色的视频网站| 精品人妻一区二区三区含羞草| 久操社区| 久综合| 国产尤物av| 国产盗摄一区二区三区| 国模精品一区| 色爱区综合| 亚洲视频1| 欧美二区视频| 台湾av在线播放| 久久免费影院| 国产56页| 久久黄色录像| 欧美大黑b| 日韩毛片基地| 色偷偷在线观看| 久久精品久久久久久久| 又骚又黄的视频| 国产一区二区不卡视频| 91麻豆一区二区| 丁香婷婷激情| 在线看一级片| avwww| 成人精品毛片| 老司机深夜福利网站| 欧美va视频| 亚洲国产黄色片| 日本91av| 特级av片| 性色tv| 在线一级视频| 成人网战| 狠狠狠狠狠干| 激情五月婷婷在线| 亚洲九九夜夜| 国产剧情在线视频| a一级黄色片| 老司机免费在线视频| 国产精品9| 99久久亚洲精品| 逼逼爱插插网站| 青青免费视频| 69av网| 在线麻豆| 新x8x8拨牐拨牐永久免费影库| 日本黄色小视频| 欧美美女啪啪| 国产精品变态另类虐交| 最新国产在线| 激情宗合网| 亚洲一级电影| 超碰婷婷| 影音先锋国产资源| 美女久久久久| 久久五月综合| 黑人操亚洲女| 日本www在线观看| 韩国三级视频在线观看| 精品欧美一区二区三区| 97插插插| 琪琪色视频| 操老女人视频| 日韩高清成人| 17草在线| 手机av网| 超碰天天干| 五月婷婷综合在线观看| 尤物videos另类xxxx| 电影《走路上学》免费| 2019自拍偷拍| 欧美69视频| 一卡二卡三卡在线观看| 69视频入口| 99自拍| 亚洲色图欧美视频| 午夜亚洲天堂| 秋霞成人网| 国产不卡免费视频| 亚洲第一页综合| 国产精品国产| 欧美色国| 免费色播| 日本v视频| 日韩深夜福利| 都市激情男人天堂| 99热这里是精品| 在线观看免费看片| 激情久久av| mdyd—856冲田杏梨在线| 国产激情在线观看| 中国美女一级看片| 狠狠久久综合| 国产欧美a| 69视频在线播放| jizz日本女人| 1024精品一区二区三区日韩| 播放男人添女人下边视频| 99精品国自产在线| 国产精品无码久久久久成人app| 在线免费你懂的| 久久午夜剧场| 蜜臀在线播放| 国产97超碰| 成人精品在线| 男人的天堂视频| 农村脱精光一级| 欧美麻豆视频| 青青草视频| 日韩精品视频免费| 夜夜夜爽| 日本骚少妇| 天天夜夜草| 婷婷在线播放| 九色porn| 神马影院午夜伦理| 精品人妻一区二区三区香蕉| 欧美福利视频一区二区| av网在线观看| wwwxxoo| 成人免费播放视频| 亚洲av片不卡无码久久| 国产精品日韩| 1024久久| 日韩在线高清视频| 国产精品999久久久| 噼里啪啦免费高清看| 欧美日韩精品久久久免费观看| 最好看的中文字幕| 最近日本中文字幕| 911香蕉| 国产精品一区二区6| 久久久久女人精品毛片九一| 精品国产麻豆| 18日本xxxxxxxxx95| 色先锋在线| 国产精品国产一区二区| 欧美操操操| 伊人网视频| 饥渴少妇勾引水电工av| 女人的天堂av在线| 亚洲欧美另类图片| 日本高清视频在线| av看片资源| 被黑人猛躁10次高潮视频| 热久久久| 国产激情第一页| 视色在线| a天堂视频| 美足av| 日本天堂网在线观看| 国产人妖ts| 欧洲视频一区| 久久国内精品| 不卡精品| chinese麻豆gay勾外卖| 在线观看黄| 国产熟妇与子伦hd| 涩涩在线看| 一级片网址| 亚洲情人网| 国产高潮国产高潮久久久91| 97影院| 91午夜视频| 老司机综合网| 纯爱无遮挡h肉动漫在线播放| 日韩在线第二页| 久久精品国产99国产 | 波多野结衣家庭主妇| 欧美与黑人午夜性猛交久久久| 一本不卡| 奇米影视播放器| 视频国产精品| av在线免费网站| 动漫美女舌吻| 88久久精品无码一区二区毛片| 在线观看免费黄视频| 欧美激情一区二区| 性欧美极品| 国产福利精品视频| 久久亚洲精| av中出| 国产一区二区精品| chinese麻豆新拍video| 麻豆精品国产传媒mv男同| 免费污片网站| 99热这里都是精品| 亚洲激情二区| 久久精品二区| 欧洲成人免费视频| 久久麻豆av| 涩涩亚洲| 色网站在线免费观看| 少妇高潮久久久| 色淫湿视频| 成人性做爰aaa片免费| 欧美xxxxx性| 色婷五月天| 成人手机看片| 日韩欧美精品在线| 亚洲成人精选| 男女扒开双腿猛进入爽爽免费 | 一级片黄色片| 涩色视频| 91婷婷色| 爱爱免费小视频| 国产精品无码粉嫩小泬| 一区二区在线| 成人性视频在线| 欧美老熟妇一区二区三区| 色噜噜综合| 高跟丝袜av| 国产片高清在线观看| 久久国产91| 日本伦理在线| 亚洲欧美日韩色图| 久久丫精品国产亚洲av不卡| 亚洲一区久久| 久久久久少妇| jlzzjlzz国产精品久久| 成人一级黄色片| 狠狠操五月天| 免费日韩一级片| 亚洲精品自拍视频| 欧美嫩交| 国产精品99精品| aaa欧美| 蜜桃成人免费视频| 四虎影院在线免费播放| 中文字幕福利| 国产免费一区二区三区三州老师| 男人操女人的视频| 美女久久久久久| 亚洲欧美综合一区| 欧美黄色录像带| 人人综合| 久久色网站| 欧美久久精品| 色欲欲www成人网站| 一品道av| 国产免费看黄| 日韩小视频| 亚洲高清不卡| 色偷偷亚洲| 精品人妻一区二区三区潮喷在线| 亚洲精品欧美| 日韩天堂网| 日本在线资源| 四虎影库永久在线| 日韩五码在线| 色人人| 国产一国产二| www.五月婷婷.com| 中文字幕乱码中文乱码777| 国产免费一区二区三区| 人妻大战黑人白浆狂泄| 国产女人18毛片水真多18| 日韩综合在线视频| 二男一女一级一片| 精品乱子伦一区二区三区| 日本黄色片视频| 国产精品一区二区性色av| 黄wwwww| 黄色免费在线观看网站| 97在线精品视频| 亚洲视频在线观看| 中日韩毛片| 久草精品在线观看| av最新地址| 国产91在线 | 亚洲| 成人深夜视频在线观看| 在线看网站| 成人av网址在线观看| 在线观看色| 午夜av片| 国产综合区| 夜夜爽天天爽| 涩涩视频免费| www好男人| 高清一区二区三区四区| 日本精品三区| av成人毛片| 97人妻一区二区精品免费视频| 久久精品99| 日日操夜夜爽| 成人动漫视频| 国产精品亚洲一区二区无码| 日本一品道| 岛国av一区二区三区| 欧美视频xxx| 久久精品视频9| 成年人国产视频| 日日草夜夜操| www.色亚洲| 色综合色综合| 97精品超碰一区二区三区| 欧美福利影院| 欧美激情视频网站| 日日操日日爽| 久草天堂| 日韩av专区| 激情综合网五月| 啪啪自拍| 国内自拍偷拍视频| 色欲av伊人久久大香线蕉影院| 免费v片在线观看| 锕锕锕锕锕锕锕锕| 日韩a在线| 天天操操操| 黄色www| 丰满大乳奶做爰ⅹxx视频| 婷婷色九月| 成年网站在线| 欧美日韩精品亚洲精品| 中文字幕观看在线| 青苹果av| 久久人人草| 伊人午夜| 又粗又大又硬毛片免费看| 69视频在线| www射| 日本美女视频网站| www欧美日韩| 日韩一区二区精品视频| 日韩午夜网站| 欧美一区二区三区在线视频| 亚洲熟女乱色一区二区三区久久久| 不卡福利视频| 欧美黑粗硬| www.香蕉视频.com| 国产精品久久影视| 四虎影院国产精品| 国产96在线| 女生喷液视频| 国产伦子伦对白视频| 久久久网| 日韩乱论| 特级西西444www大精品视频免费看| 加勒比视频在线观看| 亚洲AV成人精品| 四虎网址大全| 在线观看视频国产| 亚洲久久视频| 噜噜啪啪| 四色在线| 野外吮她的花蒂高h在线观看| 网站黄在线观看| 色网视频| 二级黄色片| 丁香激情视频| 亚洲成人午夜影院| 亚洲性生活片| 亚洲综合视频在线观看| 二级毛片| 国产亚洲一区二区三区在线观看| 亚洲成人www| 特大黑人巨交吊性xxxx视频| 91麻豆精品一区二区三区| 日本在线播放| 亚洲av网址在线| 日韩综合一区二区| 美女擦边视频| 亚洲一二三四区| 性xxxxbbbb| 黑人一级黄色片| 少妇精品无码一区二区| 免费又黄又爽又猛大片午夜| 日韩在线视屏| 夜夜嗨av禁果av粉嫩av懂色av| 欧美xxxx83d| 国产日产精品一区二区| 少女逼逼| 中文字幕第8页| 国产精品一区二区在线观看| 911亚洲精选| 成人在线综合| 自拍偷拍综合| 精品无码av在线| 精品爱爱| 911亚洲精品| 中文字幕日韩一区二区三区| 日韩免费一级| 国产乱人伦| 日本美女全裸| 91精品看片| 天海翼av| 高清视频在线免费观看| 成人综合av| 亚洲一区| 色播在线视频| youjizz欧美| 麻豆911| 国产区一区二区三区| 在线观看视频一区二区三区| 午夜视频在线观看国产| 韩国三级hd中文字幕叫床浴室| 夜间福利视频| 国产经典三级| 黄色特级视频| 亚洲av无码一区二区三区在线| 91精品导航| 午夜家庭影院| 国产淫视频| 黄视频网站在线观看| 国产精品黄| 成人xxxxx| 韩国久久久| 在线视频 日韩| 日韩欧美中文字幕在线观看| 一区二区三区小视频| a√天堂网| 内射一区二区三区| 日韩一区二区高清| 人妻精品久久久久中文字幕69| 丁香激情小说| 蜜臀尤物一区二区三区直播| 天堂网在线看| 国产av无码专区亚洲a∨毛片| 色综合免费| 五月激情婷婷丁香| 岛国毛片在线观看| 中国女人高潮hd| 老司机亚洲精品| 久久亚洲AV无码| 日韩国产毛片| 欧洲亚洲精品| 亚洲天堂aaa| 18色av| 日本欧美日韩| 亚洲中出| xxx色| 国产另类自拍| 日韩亚洲欧美在线| 色图色小说| 亚洲生活片| 国产黑丝一区| 免费小视频| 亚洲第五页| caoporn人人| 亚洲丝袜av| 狠狠操狠狠操狠狠操| 99re国产| 69超碰| 91精品国产91久久久久久| 青青草伊人网| 国产熟妇一区二区三区四区| 五月天天| 一区二区日韩电影| 一区二区不卡视频| 亚洲污视频| 毛片基地视频| 性欧美丰满熟妇xxxx性久久久| 中文在线第一页| 在线视频午夜| 136福利视频导航| 老女人一毛片| 鬼灭之刃柱训练篇在线观看| 亚洲综合三区| 波多野结衣午夜| 鲁丝av| 午夜国产在线| 日韩视频区| 裸体av淫导航| 青娱乐国产| 日韩成人精品一区二区三区| 久久91久久| 丁香六月天婷婷| www亚洲精品| 97在线观视频免费观看| 日日夜夜中文字幕| 久久午夜国产精品| 亚洲一区影院| 久久永久免费视频| 不卡中文字幕av| 黄色高清网站| 韩日黄色| 在线高清免费观看| 日本网站在线免费观看| 天天爱综合| 亚色91| 色伊人av| 天天操天天射天天舔| 久久av一区二区三区亚洲| 色妞网站| 成人免费一区| 夜夜骑天天操| 超碰资源总站| 国产中文字幕一区二区| 免费精品一区| 综合久色| 寂寞人妻瑜伽被教练日| 日韩电影一区二区三区| 婷婷丁香六月天| 狠狠做深爱婷婷综合一区| 日韩欧美在线免费| 女18毛片| 免费成人国产| 久久一级片| 无码h黄肉3d动漫在线观看| 爆操网站| 中文字幕三级电影| 成人在线观看一区| 免费jizz| 成人午夜精品视频| 黄色片免费在线播放| 少妇高潮露脸国语对白| 玉女心经是什么意思| 国语对白少妇spa私密按摩| 欧美18—19性高清hd4k| 91av在线免费| 高潮又黄又刺激| 国产自在线| 欧美福利视频在线观看| 久色精品| 永久免费精品视频| 亚洲黄色视屏| 视频在线观看免费大片| 伊人av在线| 午夜剧场福利| 欧美久久激情| 久久99久久99| a天堂在线视频| 噜噜噜噜私人影院| 手机av免费在线观看| 成色视频| 日韩国产精品一区| www.777奇米| 国产啊啊啊啊| 激情小说中文字幕| 亚洲AV无码一区二区三区性| 中文字幕视频二区| 4438x亚洲最大| 插吧插吧综合网| 一个人看的www片免费高清中文| 久中文字幕| 九色福利| 日韩最新| 男女无遮挡免费视频| 天堂伊人网| 男人懂的网站| 一起艹在线观看| 国产一区二区黄色| 人妻少妇久久中文字幕| 极品少妇一区二区| 精品国模| 国产精品wwww| 不卡的av在线播放| 国产欧美另类| 久久久久久爱| 国产青草| 黄色网在线| 成人a视频| 毛片在线网| 欧亚成人av| 2020国产精品视频| 在线观看的免费| 涩涩视屏| 成人性生交大片| 亚洲黄色片网站| 91在线视频免费| 国产精品黄色片| 天天爱天天操| 日韩在线一卡二卡| 免费精品在线| 国产手机av| 男女操网站| 中文字幕在线免费播放| 日本色视频| 99热在线播放| 日本在线色| 欧美日韩乱| 午夜久| exo妈妈mv在线播放高清免费| 中文字字幕在线| av色综合| 国产成人av一区| 欧美日韩视频在线观看一区| 精品色综合| 国产免费一区二区三区在线观看| 亚洲日本精品| 一区二区三区在线| 公肉吊粗大爽色翁浪妇视频| 小色瓷导航| 国产主播福利| 超碰国产在线观看| 樱桃香蕉视频| 欧美三级网| 亚欧三级| 伊人久久国产精品| av在线色| 亚洲性天堂| 色婷婷yy| 在线视频 亚洲| 一区二区三区蜜桃| 亚洲色图综合网| 亚洲影视一区二区三区| 在线观看国产成人| 开心激情婷婷| 亚洲a√| 日韩欧美日本| 国产又粗又黄的视频| 亚洲人在线观看| 四虎视频| 国产网址在线观看| 国产xxx在线观看| 亚洲激情四射| 欧美一区二区三区在线看| 欧美俄罗斯乱妇| 欧美三级免费| 亚洲国产第一| 亚洲精品美女视频| 在线观看va| 亚洲精品成a人| www.国产成人| 国产一级片网站| 伊人久久一区二区三区| 最污的网站| 亚洲精品系列| 在线观看免费黄视频| 亚洲成人91| 麻豆www| 麻豆成人在线视频| 老司机在线免费视频| 中文字幕无码毛片免费看| 在线中文字日产幕| 免费一级a毛片| 2020国产精品视频|