精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Vue3的defineAsyncComponent是如何實現異步組件的呢?

開發 前端
createInnerComp?函數接收兩個參數,第一個參數為要異步加載的vue組件對象。第二個參數為使用defineAsyncComponent創建的vue組件對應的vue實例。

前言

在上一篇 給我5分鐘,保證教會你在vue3中動態加載遠程組件文章中,我們通過defineAsyncComponent實現了動態加載遠程組件。這篇文章我們將通過debug源碼的方式來帶你搞清楚defineAsyncComponent是如何實現異步組件的。注:本文使用的vue版本為3.4.19

看個demo

還是一樣的套路,我們來看個defineAsyncComponent異步組件的demo。

本地子組件local-child.vue代碼如下:

<template>
  <p>我是本地組件</p>
</template>

異步子組件async-child.vue代碼如下:

<template>
  <p>我是異步組件</p>
</template>

父組件index.vue代碼如下:

<template>
  <LocalChild />
  <button @click="showAsyncChild = true">load async child</button>
  <AsyncChild v-if="showAsyncChild" />
</template>

<script setup lang="ts">
import { defineAsyncComponent, ref } from "vue";
import LocalChild from "./local-child.vue";

const AsyncChild = defineAsyncComponent(() => import("./async-child.vue"));
const showAsyncChild = ref(false);
</script>

我們這里有兩個子組件,第一個local-child.vue,他和我們平時使用的組件一樣,沒什么說的。

第二個子組件是async-child.vue,在父組件中我們沒有像普通組件local-child.vue那樣在最上面import導入,而是在defineAsyncComponent接收的回調函數中去動態import導入async-child.vue文件,這樣定義的AsyncChild組件就是異步組件。

在template中可以看到,只有當點擊load async child按鈕后才會加載異步組件AsyncChild。

我們先來看看執行效果,如下gif圖:

圖片圖片

從上面的gif圖可以看到,當我們點擊load async child按鈕后,在network面板中才會去加載異步組件async-child.vue。

defineAsyncComponent除了像上面這樣直接接收一個返回Promise的回調函數之外,還可以接收一個對象作為參數。demo代碼如下:

const AsyncComp = defineAsyncComponent({
  // 加載函數
  loader: () => import('./async-child.vue'),

  // 加載異步組件時使用的組件
  loadingComponent: LoadingComponent,
  // 展示加載組件前的延遲時間,默認為 200ms
  delay: 200,

  // 加載失敗后展示的組件
  errorComponent: ErrorComponent,
  // 如果提供了一個 timeout 時間限制,并超時了
  // 也會顯示這里配置的報錯組件,默認值是:Infinity
  timeout: 3000
})

其中對象參數有幾個字段:

  • loader字段其實對應的就是前面那種寫法中的回調函數。
  • loadingComponent為加載異步組件期間要顯示的loading組件。
  • delay為顯示loading組件的延遲時間,默認200ms。這是因為在網絡狀況較好時,加載完成得很快,加載組件和最終組件之間的替換太快可能產生閃爍,反而影響用戶感受。
  • errorComponent為加載失敗后顯示的組件。
  • timeout為超時時間。

在接下來的源碼分析中,我們還是以前面那個接收一個返回Promise的回調函數為例子進行debug調試源碼。

開始打斷點

我們在瀏覽器中接著來看父組件index.vue編譯后的代碼,很簡單,在瀏覽器中可以像vscode一樣使用command(windows中是control)+p就可以喚起一個輸入框,然后在輸入框中輸入index.vue點擊回車就可以在source面板中打開編譯后的index.vue文件了。如下圖:

圖片圖片

我們看到編譯后的index.vue文件代碼如下:

import { defineComponent as _defineComponent } from "/node_modules/.vite/deps/vue.js?v=868545d8";
import {
  defineAsyncComponent,
  ref,
} from "/node_modules/.vite/deps/vue.js?v=868545d8";
import LocalChild from "/src/components/defineAsyncComponentDemo/local-child.vue?t=1723193310324";
const _sfc_main = _defineComponent({
  __name: "index",
  setup(__props, { expose: __expose }) {
    __expose();
    const showAsyncChild = ref(false);
    const AsyncChild = defineAsyncComponent(() =>
      import("/src/components/defineAsyncComponentDemo/async-child.vue")
    );
    const __returned__ = { showAsyncChild, AsyncChild, LocalChild };
    return __returned__;
  },
});

function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  // ...省略
}

export default _export_sfc(_sfc_main, [["render", _sfc_render]]);

從上面的代碼可以看到編譯后的index.vue主要分為兩塊,第一塊為_sfc_main對象中的setup方法,對應的是我們的script模塊。第二塊為_sfc_render,也就是我們常說的render函數,對應的是template中的內容。

我們想要搞清楚defineAsyncComponent方法的原理,那么當然是給setup方法中的defineAsyncComponent方法打斷點。刷新頁面,此時代碼將會停留在斷點defineAsyncComponent方法處。

defineAsyncComponent方法

然后將斷點走進defineAsyncComponent函數內部,在我們這個場景中簡化后的defineAsyncComponent函數代碼如下:

function defineAsyncComponent(source) {
  if (isFunction(source)) {
    source = { loader: source };
  }
  const { loader, loadingComponent, errorComponent, delay = 200 } = source;
  let resolvedComp;

  const load = () => {
    return loader()
      .catch(() => {
        // ...省略
      })
      .then((comp) => {
        if (
          comp &&
          (comp.__esModule || comp[Symbol.toStringTag] === "Module")
        ) {
          comp = comp.default;
        }
        resolvedComp = comp;
        return comp;
      });
  };

  return defineComponent({
    name: "AsyncComponentWrapper",
    setup() {
      const instance = currentInstance;
      const loaded = ref(false);
      const error = ref();
      const delayed = ref(!!delay);
      if (delay) {
        setTimeout(() => {
          delayed.value = false;
        }, delay);
      }
      load()
        .then(() => {
          loaded.value = true;
        })
        .catch((err) => {
          onError(err);
          error.value = err;
        });
      return () => {
        if (loaded.value && resolvedComp) {
          return createInnerComp(resolvedComp, instance);
        } else if (error.value && errorComponent) {
          return createVNode(errorComponent, {
            error: error.value,
          });
        } else if (loadingComponent && !delayed.value) {
          return createVNode(loadingComponent);
        }
      };
    },
  });
}

從上面的代碼可以看到defineAsyncComponent分為三部分。

  • 第一部分為:處理傳入的參數。
  • 第二部分為:load函數用于加載異步組件。
  • 第三部分為:返回defineComponent定義的組件。

第一部分:處理傳入的參數

我們看第一部分:處理傳入的參數。代碼如下:

function defineAsyncComponent(source) {
  if (isFunction(source)) {
    source = { loader: source };
  }
  const { loader, loadingComponent, errorComponent, delay = 200 } = source;
  let resolvedComp;
  // ...省略
}

首先使用isFunction(source)判斷傳入的source是不是函數,如果是函數,那么就將source重寫為包含loader字段的對象:source = { loader: source }。然后使用const { loader, loadingComponent, errorComponent, delay = 200 } = source解構出對應的loading組件、加載失敗組件、延時時間。

看到這里我想你應該明白了為什么defineAsyncComponent函數接收的參數可以是一個回調函數,也可以是包含loader、loadingComponent、errorComponent等字段的對象。因為如果我們傳入的是回調函數,在內部會將傳入的回調函數賦值給loader字段。不過loading組件、加載失敗組件等參數不會有值,只有delay延時時間默認給了200。

接著就是定義了load函數用于加載異步組件,這個函數是在第三部分的defineComponent中調用的,所以我們先來講defineComponent函數部分。

第三部分:返回defineComponent定義的組件

我們來看看defineAsyncComponent的返回值,是一個defineComponent定義的組件,代碼如下:

function defineAsyncComponent(source) {
  // ...省略

  return defineComponent({
    name: "AsyncComponentWrapper",
    setup() {
      const instance = currentInstance;
      const loaded = ref(false);
      const error = ref();
      const delayed = ref(!!delay);
      if (delay) {
        setTimeout(() => {
          delayed.value = false;
        }, delay);
      }
      load()
        .then(() => {
          loaded.value = true;
        })
        .catch((err) => {
          onError(err);
          error.value = err;
        });
      return () => {
        if (loaded.value && resolvedComp) {
          return createInnerComp(resolvedComp, instance);
        } else if (error.value && errorComponent) {
          return createVNode(errorComponent, {
            error: error.value,
          });
        } else if (loadingComponent && !delayed.value) {
          return createVNode(loadingComponent);
        }
      };
    },
  });
}

defineComponent函數的接收的參數是一個vue組件對象,返回值也是一個vue組件對象。他其實沒有做什么事情,單純的只是提供ts的類型推導。

我們接著來看vue組件對象,對象中只有兩個字段:name屬性和setup函數。

name屬性大家都很熟悉,表示當前vue組件的名稱。

大家平時<script setup>語法糖用的比較多,這個語法糖經過編譯后就是setup函數,當然vue也支持讓我們自己手寫setup函數。

提個問題:setup函數對應的是<script setup>,我們平時寫代碼都有template模塊對應的是視圖部分,也就是熟悉的render函數。為什么這里沒有render函數呢?

給setup函數打個斷點,當渲染異步組件時會去執行這個setup函數。代碼將會停留在setup函數的斷點處。

在setup函數中首先使用ref定義了三個響應式變量:loaded、error、delayed。

  • loaded是一個布爾值,作用是記錄異步組件是否加載完成。
  • error記錄的是加載失敗時記錄的錯誤信息,如果同時傳入了errorComponent組件,在加載異步組件失敗時就會顯示errorComponent組件。
  • delayed也是一個布爾值,由于loading組件不是立馬就顯示的,而是延時一段時間后再顯示。這個delayed布爾值記錄的是是當前是否還在延時階段,如果是延時階段那么就不顯示loading組件。

接下來判斷傳入的參數中設置設置了delay延遲,如果是就使用setTimeout延時delay毫秒才將delayed的值設置為false,當delayed的值為false后,在loading階段才會去顯示loading組件。代碼如下:

if (delay) {
  setTimeout(() => {
    delayed.value = false;
  }, delay);
}

接下來就是執行load函數,這個load函數就是我們前面說的defineAsyncComponent函數中的第二部分代碼。代碼如下:

load()
  .then(() => {
    loaded.value = true;
  })
  .catch((err) => {
    onError(err);
    error.value = err;
  });

從上面的代碼可以看到load函數明顯返回的是一個Promise,所以才可以在后面使用.then()和.catch()。并且這里在.then()中將loaded的值設置為true,將斷點走進load函數,代碼如下:

const load = () => {
  return loader()
    .catch(() => {
      // ...省略
    })
    .then((comp) => {
      if (
        comp &&
        (comp.__esModule || comp[Symbol.toStringTag] === "Module")
      ) {
        comp = comp.default;
      }
      resolvedComp = comp;
      return comp;
    });
};

這里的load函數代碼也很簡單,在里面直接執行loader函數。還記得這個loader函數是什么嗎?

defineAsyncComponent函數可以接收一個異步加載函數,這個異步加載函數可以在運行時去import導入組件。這個異步加載函數就是這里的loader函數,執行loader函數就會去加載異步組件。在我們這里是異步加載async-child.vue組件,代碼如下:

const AsyncChild = defineAsyncComponent(() => import("./async-child.vue"));

所以這里執行loader函數就是在執行() => import("./async-child.vue"),執行了import()后就可以在network面板看到加載async-child.vue文件的網絡請求。import()返回的是一個Promise,等import的文件加載完了后就會觸發Promise的then(),所以這里的then()在此時不會觸發。

接著將斷點走出load函數回到setup函數的最后一個return部分,代碼如下:

setup() {
  // ...省略
  return () => {
    if (loaded.value && resolvedComp) {
      return createInnerComp(resolvedComp, instance);
    } else if (error.value && errorComponent) {
      return createVNode(errorComponent, {
        error: error.value,
      });
    } else if (loadingComponent && !delayed.value) {
      return createVNode(loadingComponent);
    }
  };
},

注意看,這里的setup的返回值是一個函數,不是我們經??匆姷膶ο?。由于這里返回的是函數,此時代碼將不會走到返回的函數里面去,給return的函數打個斷點。我們暫時先不看函數中的內容,讓斷點走出setup函數。發現setup函數是由vue中的setupStatefulComponent函數調用的,在我們這個場景中簡化后的setupStatefulComponent函數代碼如下:

function setupStatefulComponent(instance) {
  const Component = instance.type;
  const { setup } = Component;
  const setupResult = callWithErrorHandling(setup, instance, 0, [
    instance.props,
    setupContext,
  ]);
  handleSetupResult(instance, setupResult);
}

上面的callWithErrorHandling函數從名字你應該就能看出來,調用一個函數并且進行錯誤處理。在這里就是調用setup函數,然后將調用setup函數的返回值丟給handleSetupResult函數處理。

將斷點走進handleSetupResult函數,在我們這個場景中handleSetupResult函數簡化后的代碼如下:

function handleSetupResult(instance, setupResult) {
  if (isFunction(setupResult)) {
    instance.render = setupResult;
  }
}

在前面我們講過了我們這個場景setup函數的返回值是一個函數,所以isFunction(setupResult)的值為true。代碼將會走到instance.render = setupResult,這里的instance是當前vue組件實例,執行這個后就會將setupResult賦值給render函數。

我們知道render函數一般是由template模塊編譯而來的,執行render函數就會生成虛擬DOM,最后由虛擬DOM生成對應的真實DOM。

當setup的返回值是一個函數時,這個函數就會作為組件的render函數。這也就是為什么前面defineComponent中只有name熟悉和setup函數,卻沒有render函數。

在執行render函數生成虛擬DOM時就會去執行setup返回的函數,由于我們前面給返回的函數打了一個斷點,所以代碼將會停留在setup返回的函數中?;仡櫼幌聅etup返回的函數代碼如下:

setup() {
  // ...省略
  return () => {
    if (loaded.value && resolvedComp) {
      return createInnerComp(resolvedComp, instance);
    } else if (error.value && errorComponent) {
      return createVNode(errorComponent, {
        error: error.value,
      });
    } else if (loadingComponent && !delayed.value) {
      return createVNode(loadingComponent);
    }
  };
},

由于此時還沒將異步組件加載完,所以loaded的值也是false,此時代碼不會走進第一個if中。

同樣的組件都還沒加載完也不會有error,代碼也不會走到第一個else if中。

如果我們傳入了loading組件,此時代碼也不會走到第二個else if中。因為此時的delayed的值還是true,代表還在延時階段。只有等到前面setTimeout的回調執行后才會將delayed的值設置為false。

并且由于delayed是一個ref響應式變量,所以在setTimeout的回調中改變了delayed的值就會重新渲染,也就是再次執行render函數。前面講了這里的render函數就是setup中返回的函數,代碼就會重新走到第二個else if中。

此時else if (loadingComponent && !delayed.value),其中的loadingComponent是loading組件,并且delayed.value的值也是false了。代碼就會走到createVNode(loadingComponent)中,執行這個函數就會將loading組件渲染到頁面上。

加載異步組件

前面我們講過了在渲染異步組件時會執行load函數,在里面其實就是執行() => import("./async-child.vue")加載異步組件async-child.vue,我們也可以在network面板中看到多了一個async-child.vue文件的請求。

我們知道import()的返回值是一個Promise,當文件加載完成后就會觸發Promise的then()。此時代碼將會走到第一個then()中,回憶一下代碼:

const load = () => {
  return loader()
    .catch(() => {
      // ...省略
    })
    .then((comp) => {
      if (
        comp &&
        (comp.__esModule || comp[Symbol.toStringTag] === "Module")
      ) {
        comp = comp.default;
      }
      resolvedComp = comp;
      return comp;
    });
};

在then()中判斷加載進來的文件是不是一個es6的模塊,如果是就將模塊的default導出重寫到comp組件對象中。并且將加載進來的vue組件對象賦值給resolvedComp變量。

執行完第一個then()后代碼將會走到第二個then()中,回憶一下代碼:

load()
  .then(() => {
    loaded.value = true;
  })

第二個then()代碼很簡單,將loaded變量的值設置為true,也就是標明已經將異步組件加載完啦。由于loaded是一個響應式變量,改變他的值就會導致頁面重新渲染,將會再次執行render函數。前面我們講了這里的render函數就是setup中返回的函數,代碼就會重新走到第二個else if中。

再來回顧一下setup中返回的函數,代碼如下:

setup() {
  // ...省略
  return () => {
    if (loaded.value && resolvedComp) {
      return createInnerComp(resolvedComp, instance);
    } else if (error.value && errorComponent) {
      return createVNode(errorComponent, {
        error: error.value,
      });
    } else if (loadingComponent && !delayed.value) {
      return createVNode(loadingComponent);
    }
  };
},

由于此時loaded的值為true,并且resolvedComp的值為異步加載vue組件對象,所以這次render函數返回的虛擬DOM將是createInnerComp(resolvedComp, instance)的執行結果。

createInnerComp函數

接著將斷點走進createInnerComp函數,在我們這個場景中簡化后的代碼如下:

function createInnerComp(comp, parent) {
  const { ref: ref2, props, children } = parent.vnode;
  const vnode = createVNode(comp, props, children);
  vnode.ref = ref2;
  return vnode;
}

createInnerComp函數接收兩個參數,第一個參數為要異步加載的vue組件對象。第二個參數為使用defineAsyncComponent創建的vue組件對應的vue實例。

然后就是執行createVNode函數,這個函數大家可能有所耳聞,vue提供的h()函數其實就是調用的createVNode函數。

在我們這里createVNode函數接收的第一個參數為子組件對象,第二個參數為要傳給子組件的props,第三個參數為要傳給子組件的children。createVNode函數會根據這三個參數生成對應的異步組件的虛擬DOM,將生成的異步組件的虛擬DOM進行return返回,最后就是根據虛擬DOM生成真實DOM將異步組件渲染到頁面上。如下圖(圖后還有一個總結):

圖片圖片

總結

本文講了defineAsyncComponent是如何實現異步組件的:

  • 在defineAsyncComponent函數中會返回一個vue組件對象,對象中只有name屬性和setup函數。
  • 當渲染異步組件時會執行setup函數,在setup函數中會執行內置的一個load方法。在load方法中會去執行由defineAsyncComponent定義的異步組件加載函數,這個加載函數的返回值是一個Promise,異步組件加載完成后就會觸發Promise的then()。
  • 在setup函數中會返回一個函數,這個函數將會是組件的render函數。
  • 當異步組件加載完了后會走到前面說的Promise的then()方法中,在里面會將loaded響應式變量的值修改為true。
  • 修改了響應式變量的值導致頁面重新渲染,然后執行render函數。前面講過了此時的render函數是setup函數中會返回的回調函數。執行這個回調函數會調用createInnerComp函數生成異步組件的虛擬DOM,最后就是根據虛擬DOM生成真實DOM,從而將異步子組件渲染到頁面上。
責任編輯:武曉燕 來源: 前端歐陽
相關推薦

2021-05-18 07:51:37

Suspense組件Vue3

2021-09-29 11:33:19

異步組件Vue 3

2024-08-07 10:16:00

2021-08-01 07:58:58

Vue 加載組件

2021-12-02 05:50:35

Vue3 插件Vue應用

2024-03-13 08:37:18

Vue3Suspense異步組件

2024-01-23 09:15:33

Vue3組件拖拽組件內容編輯

2020-12-01 08:34:31

Vue3組件實踐

2022-01-19 18:05:47

Vue3前端代碼

2022-07-27 08:40:06

父子組件VUE3

2023-04-02 10:06:24

組件vue3sign2.

2023-11-28 09:03:59

Vue.jsJavaScript

2024-02-01 09:10:04

頁面引導工具Vue3

2024-01-08 08:50:19

Vue3級聯菜單數據懶加載

2023-04-27 11:07:24

Setup語法糖Vue3

2024-05-28 08:02:08

Vue3父組件子組件

2022-09-20 11:00:14

Vue3滾動組件

2024-03-21 08:34:49

Vue3WebSocketHTTP

2024-07-30 08:59:22

2022-03-10 11:04:04

Vue3Canvas前端
點贊
收藏

51CTO技術棧公眾號

少妇一级淫片免费放中国| 国产另类第一区| 少妇视频在线播放| 婷婷久久免费视频| 亚洲老司机在线| 成人午夜激情免费视频| 免费在线观看日韩| 国产成人高清精品免费5388| 一区二区三区在线免费观看| 国产经典一区二区三区| 精品国产乱码一区二区| 精品福利久久久| 在线综合视频播放| 久久久久久久久久伊人| 四虎免费在线观看| 日本aⅴ亚洲精品中文乱码| 久久天天躁狠狠躁夜夜躁| 国产999免费视频| 久久青草伊人| 成人欧美一区二区三区视频网页 | www.黄色com| 国产精品亚洲欧美一级在线| 亚洲制服丝袜一区| 天堂社区 天堂综合网 天堂资源最新版| 中文字幕丰满人伦在线| 亚洲国产综合在线看不卡| 亚洲午夜色婷婷在线| 天堂av在线8| 漫画在线观看av| 亚洲欧洲日韩综合一区二区| 国产在线一区二区三区欧美| 中日韩在线观看视频| 亚洲国产电影| 精品国偷自产在线视频| av鲁丝一区鲁丝二区鲁丝三区| 在线免费看h| 一区二区三区中文字幕精品精品| 欧美日韩国产一二| 免费a视频在线观看| 免费在线看成人av| 91精品国产91久久久久久不卡| 人人爽人人爽人人片| 国产精品qvod| 欧美视频日韩视频| 99精品免费在线观看| 啦啦啦中文在线观看日本| 中日韩av电影| 日韩成人av网站| 色噜噜一区二区三区| 日韩精品91亚洲二区在线观看| 美女精品视频一区| 丁香激情五月少妇| 婷婷综合一区| 精品国产三级电影在线观看| 亚洲美女性囗交| 久久精品超碰| 在线观看不卡视频| 无码aⅴ精品一区二区三区浪潮 | 在线观看日本中文字幕| 五月天亚洲一区| 亚洲女成人图区| 欧洲女同同性吃奶| jiujiure精品视频播放| 色婷婷**av毛片一区| 999精品久久久| 91九色精品| 欧美精品情趣视频| 欧美激情精品久久| 日韩午夜免费| 国产999精品| 夜夜躁狠狠躁日日躁av| 国内精品伊人久久久久影院对白| 91最新在线免费观看| 性欧美8khd高清极品| 成人精品国产免费网站| 久久综合九九| 波多野结衣一区二区| √…a在线天堂一区| www.日本三级| 中老年在线免费视频| 在线视频国内一区二区| 色乱码一区二区三区在线| 精品欧美视频| 日韩av在线资源| 欧洲性xxxx| 午夜日本精品| 日本伊人精品一区二区三区介绍 | h片在线观看视频免费免费| 欧美日韩国产中文字幕| 亚洲少妇久久久| 91精品尤物| 亚洲美女av在线播放| 香蕉成人在线视频| 亚洲一级特黄| 国产乱人伦真实精品视频| 性做久久久久久久久久| 久久久久久久综合色一本| 日本一二三区视频在线| 亚洲欧洲美洲av| 欧美丰满少妇xxxbbb| 亚洲av无码一区二区三区观看 | 日本精品福利视频| 成人性生交大片免费网站| 7777精品伊人久久久大香线蕉完整版 | 精品视频一区二区三区| 亚洲美女动态图120秒| av成人免费网站| 久久国产精品久久w女人spa| 91最新国产视频| 成人在线高清视频| 亚洲成人动漫精品| 91免费视频污| 成人一二三区| 7m精品福利视频导航| a级片免费观看| 国产嫩草影院久久久久| 日本a视频在线观看| 91精品国产色综合久久不卡粉嫩| 亚洲欧美国产va在线影院| 久草网在线观看| 精品一区二区免费看| 久久久久久九九九九| 婷婷丁香在线| 3d成人动漫网站| 免费看日本黄色片| 丝袜国产日韩另类美女| 国模精品娜娜一二三区| 性欧美video高清bbw| 337p亚洲精品色噜噜噜| 国产精品www爽爽爽| 免费亚洲视频| 久久久久久国产精品免费免费| 黑人极品ⅴideos精品欧美棵| 在线电影院国产精品| 国产亚洲无码精品| 亚洲国产精品一区制服丝袜| 91在线网站视频| 欧美13一16娇小xxxx| 欧美优质美女网站| 性猛交娇小69hd| 久久精品盗摄| 欧美精品亚洲精品| 国模精品视频| 亚洲激情视频在线播放| 日韩女优在线观看| 91亚洲男人天堂| 免费看的黄色大片| 亚洲自拍电影| 国产极品精品在线观看| 暖暖视频在线免费观看| 精品人伦一区二区三区蜜桃网站| 又黄又爽的网站| 亚洲精品专区| 蜜桃麻豆91| 天天免费亚洲黑人免费| 在线观看国产精品淫| 在线免费av片| 亚洲免费大片在线观看| xxxx国产视频| 亚洲美女黄网| 欧美日韩在线高清| 日本成人在线网站| 欧美成人免费全部| 秋霞网一区二区| 丁香五六月婷婷久久激情| 伊人网在线视频观看| 秋霞午夜av一区二区三区| 亚洲一区二区精品在线| 精品国产一区二| 午夜精品蜜臀一区二区三区免费| 日色在线视频| 欧美视频完全免费看| 亚洲综合视频网站| 99re成人在线| 怡红院亚洲色图| 黄色国产精品| 日本不卡一二三区| 青草伊人久久| 欧美专区第一页| 在线看黄色av| 亚洲第一精品自拍| 奴色虐av一区二区三区| 亚洲欧美视频一区| 国产精品815.cc红桃| 久久99精品国产91久久来源| 一卡二卡三卡视频| 欧美一站二站| 国产精品一区二区欧美| 福利一区二区三区视频在线观看 | 国产又粗又硬又长又爽| 成人动漫精品一区二区| 日本在线观看免费视频| 黄色日韩在线| 一区二区不卡在线| 色婷婷久久久| 3d精品h动漫啪啪一区二区| 小早川怜子影音先锋在线观看| 日韩一区视频在线| 99riav国产| 欧美写真视频网站| 黄色一级片免费看| 亚洲欧美精品午睡沙发| 在线免费观看麻豆| 国产福利一区二区三区视频在线 | 国产精品免费av一区二区| 国产精品免费视频网站| 91黄色免费视频| 国产一区二区三区四| 日韩中文字幕免费在线| 精品av久久久久电影| 一区二区三区四区视频在线观看 | 天堂v在线视频| 中文精品一区二区| 国产精品视频免费一区二区三区| 国产成人免费| 国产精品成人品| 在线看片福利| 97超级碰碰碰| 2021天堂中文幕一二区在线观| 日韩一区二区精品视频| 美女毛片在线看| 日韩精品一区二区三区第95| 亚洲黄色片视频| 91精品黄色片免费大全| 少妇无套内谢久久久久| 色成人在线视频| 在线观看国产亚洲| 五月婷婷综合网| 久久久国产精华液| 亚洲免费在线电影| 亚洲精品久久久久久国| 国产精品丝袜久久久久久app| 无码熟妇人妻av| 91网站在线播放| 亚洲av成人片色在线观看高潮| 成人久久久精品乱码一区二区三区 | 日本公妇乱淫免费视频一区三区| 欧美网色网址| 久久精品五月婷婷| 欧美激情极品| 久久综合精品一区| 国产精选一区| 亚洲ai欧洲av| 久久高清免费| 国产高清精品软男同| 久久久久久久久久久9不雅视频| 亚洲人一区二区| 先锋资源久久| 中国女人做爰视频| 国产综合精品一区| 日韩国产一级片| 亚洲国产午夜| 国内自拍在线观看| 日韩成人一级片| 污污网站在线观看视频| 国产精品99久久久久久有的能看 | 日韩中文字幕视频网| 91在线免费看片| 九色丨蝌蚪丨成人| 日本高清久久一区二区三区| 色中色综合网| 日韩欧美猛交xxxxx无码| 亚洲第一在线| 超碰网在线观看| 麻豆精品在线播放| 伦伦影院午夜理论片| 成人激情av网| 怡红院一区二区三区| 亚洲色图欧洲色图| 国产午夜福利一区二区| 日本久久一区二区| 一二三四区在线| 欧美成人免费网站| 欧美精品少妇| 最近2019年手机中文字幕| 岛国中文字幕在线| 2019亚洲日韩新视频| 777午夜精品电影免费看| 亚洲最大福利网| 婷婷综合电影| 国产精品久久成人免费观看| 精品白丝av| 五月婷婷六月丁香激情| 国产91高潮流白浆在线麻豆| 亚洲av无码一区二区二三区| 国产精品高潮呻吟久久| 国产乡下妇女做爰视频| 欧美日韩在线三区| 人妻夜夜爽天天爽| 最近的2019中文字幕免费一页| 色屁屁www国产馆在线观看| 国产成人亚洲综合青青| 亚洲不卡视频| 日韩久久久久久久| 精品电影一区| 亚洲一区二区三区四区五区| 91一区二区在线观看| 欧美丰满熟妇bbbbbb| 91久久免费观看| 人人妻人人澡人人爽精品日本| 上原亚衣av一区二区三区| 黄色aa久久| www.成人av.com| 91欧美大片| 可以在线看的黄色网址| 成人免费视频国产在线观看| 在线观看黄网址| 91精品福利视频| 香蕉视频黄色片| 九九热最新视频//这里只有精品| 日本中文字幕一区二区| 久久99精品久久久久久青青日本 | 91极品视频在线| 久久久久久久久成人| 四虎一区二区| 免费永久网站黄欧美| 黑森林av导航| 亚洲视频中文字幕| 中文天堂在线视频| 亚洲女人初尝黑人巨大| 两个人看的在线视频www| av一本久道久久波多野结衣| 国产韩日影视精品| 污视频免费在线观看网站| 久久久久亚洲综合| 天天操天天操天天操天天| 亚洲成人网在线| 欧美韩日亚洲| 国产 高清 精品 在线 a| 亚洲一区 二区 三区| 免费成人黄色大片| 国产精品久久久久久久久搜平片| 青青草视频在线观看免费| 日韩黄色高清视频| 高潮在线视频| 国产在线精品一区二区三区》| 伊人久久大香线蕉综合热线| 国产伦理在线观看| 亚洲午夜视频在线观看| а√中文在线资源库| 欧美不卡视频一区发布| 国产免费av国片精品草莓男男| 一区二区日本| 国产一区欧美一区| wwwav国产| 精品三级av在线| wwww亚洲| 欧美成ee人免费视频| 免费精品视频| 欧美福利第一页| 欧美影院午夜播放| 久cao在线| 国产高清自拍一区| 亚洲在线日韩| 欧美日韩高清丝袜| 日本精品一区二区三区四区的功能| 国产毛片av在线| 国产中文字幕亚洲| 综合日韩在线| 亚洲欧美高清在线| 狠狠久久亚洲欧美专区| 国产h视频在线观看| 国产在线观看91精品一区| 雨宫琴音一区二区三区| 无码av免费精品一区二区三区| 午夜精品久久久久久不卡8050| 你懂得在线网址| 91久久在线观看| 在线 亚洲欧美在线综合一区| 黄色工厂在线观看| 欧美日韩国产综合久久| 新版中文在线官网| 久久久久久亚洲精品不卡4k岛国| 三级在线观看一区二区| 51精品免费网站| 亚洲精品在线网站| 黄色精品视频| 国产尤物av一区二区三区| 久久女同互慰一区二区三区| 一本色道久久综合熟妇| 高清欧美性猛交xxxx| 国产欧美日韩在线观看视频| 日本黄色一级网站| 欧美午夜美女看片| 国产精品一区二区三区视频网站| 国产在线精品一区二区三区》 | 欧美日韩国产中文字幕| 97人人在线| 国产一区二区免费在线观看| 日本大胆欧美人术艺术动态| 久久久久久国产精品免费播放| 亚洲人成电影在线观看天堂色| 视频在线亚洲| 色婷婷狠狠18| 午夜影院久久久| 国产在线观看av| 欧美日韩精品免费在线观看视频| 国产高清久久久久| 中文字幕在线网址| 欧美专区日韩视频|