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

Vue 3.0 進階之動態組件探秘

開發 前端
本文是 Vue 3.0 進階系列 的第四篇文章,在這篇文章中,阿寶哥將介紹 Vue 3 中的內置組件 —— component,該組件的作用是渲染一個 “元組件” 為動態組件。

 [[383029]]

本文轉載自微信公眾號「全棧修仙之路」,作者全棧修仙之路。轉載本文請聯系全棧修仙之路公眾號。 

本文是 Vue 3.0 進階系列 的第四篇文章,在這篇文章中,阿寶哥將介紹 Vue 3 中的內置組件 —— component,該組件的作用是渲染一個 “元組件” 為動態組件。如果你對動態組件還不了解的話也沒關系,文中阿寶哥會通過具體的示例,來介紹動態組件的應用。

由于動態組件內部與組件注冊之間有一定的聯系,所以為了讓大家能夠更好地了解動態組件的內部原理,阿寶哥會先介紹組件注冊的相關知識。

一、組件注冊

1.1 全局注冊

在 Vue 3.0 中,通過使用 app 對象的 component 方法,可以很容易地注冊或檢索全局組件。component 方法支持兩個參數:

  • name:組件名稱;
  • component:組件定義對象。

接下來,我們來看一個簡單的示例:

  1. <div id="app"
  2.    <component-a></component-a> 
  3.    <component-b></component-b> 
  4.    <component-c></component-c> 
  5. </div> 
  6. <script> 
  7.    const { createApp } = Vue 
  8.    const app = createApp({}); // ① 
  9.    app.component('component-a', { // ② 
  10.      template: "<p>我是組件A</p>" 
  11.    }); 
  12.    app.component('component-b', { 
  13.      template: "<p>我是組件B</p>" 
  14.    }); 
  15.    app.component('component-c', { 
  16.      template: "<p>我是組件C</p>" 
  17.    }); 
  18.    app.mount('#app') // ③ 
  19. </script> 

在以上代碼中,我們通過 app.component 方法注冊了 3 個組件,這些組件都是全局注冊的 。也就是說它們在注冊之后可以用在任何新創建的組件實例的模板中。

該示例的代碼比較簡單,主要包含 3 個步驟:創建 App 對象、注冊全局組件和應用掛載。其中創建 App 對象的細節,阿寶哥會在后續的文章中單獨介紹,下面我們將重點分析其他 2 個步驟,首先我們先來分析注冊全局組件的過程。

1.2 注冊全局組件的過程

在以上示例中,我們使用 app 對象的 component 方法來注冊全局組件:

  1. app.component('component-a', { 
  2.   template: "<p>我是組件A</p>" 
  3. }); 

當然,除了注冊全局組件之外,我們也可以注冊局部組件,因為組件中也接受一個 components 的選項:

  1. const app = Vue.createApp({ 
  2.   components: { 
  3.     'component-a': ComponentA, 
  4.     'component-b': ComponentB 
  5.   } 
  6. }) 

需要注意的是,局部注冊的組件在其子組件中是不可用的。接下來,我們來繼續介紹注冊全局組件的過程。對于前面的示例來說,我們使用的 app.component 方法被定義在 runtime-core/src/apiCreateApp.ts 文件中:

  1. export function createAppAPI<HostElement>( 
  2.   render: RootRenderFunction, 
  3.   hydrate?: RootHydrateFunction 
  4. ): CreateAppFunction<HostElement> { 
  5.   return function createApp(rootComponent, rootProps = null) { 
  6.     const context = createAppContext() 
  7.     const installedPlugins = new Set() 
  8.     let isMounted = false 
  9.  
  10.     const app: App = (context.app = { 
  11.       // 省略部分代碼 
  12.       _context: context, 
  13.  
  14.       // 注冊或檢索全局組件 
  15.       component(name: string, component?: Component): any { 
  16.         if (__DEV__) { 
  17.           validateComponentName(name, context.config) 
  18.         } 
  19.         if (!component) { // 獲取name對應的組件 
  20.           return context.components[name
  21.         } 
  22.         if (__DEV__ && context.components[name]) { // 重復注冊提示 
  23.           warn(`Component "${name}" has already been registered in target app.`) 
  24.         } 
  25.         context.components[name] = component // 注冊全局組件 
  26.         return app 
  27.       }, 
  28.     }) 
  29.  
  30.     return app 
  31.   } 

當所有的組件都注冊成功之后,它們會被保存到 context 對象的 components 屬性中,具體如下圖所示:

顧名思義 context 是表示應用的上下文對象,那么該對象是如何創建的呢?其實,該對象是通過 createAppContext 函數來創建的:

  1. const context = createAppContext() 

而 createAppContext 函數被定義在 runtime-core/src/apiCreateApp.ts 文件中:

  1. // packages/runtime-core/src/apiCreateApp.ts 
  2. export function createAppContext(): AppContext { 
  3.   return { 
  4.     app: null as any
  5.     config: { // 應用的配置對象 
  6.       isNativeTag: NO
  7.       performance: false
  8.       globalProperties: {}, 
  9.       optionMergeStrategies: {}, 
  10.       isCustomElement: NO
  11.       errorHandler: undefined, 
  12.       warnHandler: undefined 
  13.     }, 
  14.     mixins: [], // 保存應用內的混入 
  15.     components: {}, // 保存全局組件的信息 
  16.     directives: {}, // 保存全局指令的信息 
  17.     provides: Object.create(null
  18.   } 

分析完 app.component 方法之后,是不是覺得組件注冊的過程還是挺簡單的。那么對于已注冊的組件,何時會被使用呢?要回答這個問題,我們就需要分析另一個步驟 —— 應用掛載。

1.3 應用掛載的過程

為了更加直觀地了解應用掛載的過程,阿寶哥利用 Chrome 開發者工具的 Performance 標簽欄,記錄了應用掛載的主要過程:

在上圖中我們發現了一個與組件相關的函數 resolveComponent。很明顯,該函數用于解析組件,且該函數在 render 方法中會被調用。在源碼中,我們找到了該函數的定義:

  1. // packages/runtime-core/src/helpers/resolveAssets.ts 
  2. const COMPONENTS = 'components' 
  3.  
  4. export function resolveComponent(name: string): ConcreteComponent | string { 
  5.   return resolveAsset(COMPONENTS, name) || name 

由以上代碼可知,在 resolveComponent 函數內部,會繼續調用 resolveAsset 函數來執行具體的解析操作。在分析 resolveAsset 函數的具體實現之前,我們在 resolveComponent 函數內部加個斷點,來一睹 render 方法的 “芳容”:

在上圖中,我們看到了解析組件的操作,比如 _resolveComponent("component-a")。前面我們已經知道在 resolveComponent 函數內部會繼續調用 resolveAsset 函數,該函數的具體實現如下:

  1. // packages/runtime-core/src/helpers/resolveAssets.ts 
  2. function resolveAsset( 
  3.   type: typeof COMPONENTS | typeof DIRECTIVES, 
  4.   name: string, 
  5.   warnMissing = true 
  6. ) { 
  7.   const instance = currentRenderingInstance || currentInstance 
  8.   if (instance) { 
  9.     const Component = instance.type 
  10.     // 省略大部分處理邏輯 
  11.     const res = 
  12.       // 局部注冊 
  13.       // check instance[type] first for components with mixin or extends. 
  14.       resolve(instance[type] || (Component as ComponentOptions)[type], name) || 
  15.       // 全局注冊 
  16.       resolve(instance.appContext[type], name
  17.     return res 
  18.   } else if (__DEV__) { 
  19.     warn( 
  20.       `resolve${capitalize(type.slice(0, -1))} ` + 
  21.         `can only be used in render() or setup().` 
  22.     ) 
  23.   } 

因為注冊組件時,使用的是全局注冊的方式,所以解析的過程會執行 resolve(instance.appContext[type], name) 該語句,其中 resolve 方法的定義如下:

  1. // packages/runtime-core/src/helpers/resolveAssets.ts 
  2. function resolve(registry: Record<string, any> | undefined, name: string) { 
  3.   return ( 
  4.     registry && 
  5.     (registry[name] || 
  6.       registry[camelize(name)] || 
  7.       registry[capitalize(camelize(name))]) 
  8.   ) 

分析完以上的處理流程,我們在解析全局注冊的組件時,會通過 resolve 函數從應用的上下文對象中獲取已注冊的組件對象。

  1. (function anonymous() { 
  2.     const _Vue = Vue 
  3.  
  4.     return function render(_ctx, _cache) { 
  5.         with (_ctx) { 
  6.           const {resolveComponent: _resolveComponent, createVNode: _createVNode,  
  7.             Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock} = _Vue 
  8.  
  9.             const _component_component_a = _resolveComponent("component-a"
  10.             const _component_component_b = _resolveComponent("component-b"
  11.             const _component_component_c = _resolveComponent("component-c"
  12.  
  13.             return (_openBlock(), 
  14.             _createBlock(_Fragment, null, [ 
  15.               _createVNode(_component_component_a),  
  16.               _createVNode(_component_component_b),  
  17.               _createVNode(_component_component_c)], 64)) 
  18.         } 
  19.     } 
  20. }) 

在獲取到組件之后,會通過 _createVNode 函數創建 VNode 節點。然而,關于 VNode 是如何被渲染成真實的 DOM 元素這個過程,阿寶哥就不繼續往下介紹了,后續會寫專門的文章來單獨介紹這塊的內容,接下來我們將介紹動態組件的相關內容。

二、動態組件

在 Vue 3 中為我們提供了一個 component 內置組件,該組件可以渲染一個 “元組件” 為動態組件。根據 is 的值,來決定哪個組件被渲染。如果 is 的值是一個字符串,它既可以是 HTML 標簽名稱也可以是組件名稱。對應的使用示例如下:

  1. <!--  動態組件由 vm 實例的 `componentId` property 控制 --> 
  2. <component :is="componentId"></component> 
  3.  
  4. <!-- 也能夠渲染注冊過的組件或 prop 傳入的組件--> 
  5. <component :is="$options.components.child"></component> 
  6.  
  7. <!-- 可以通過字符串引用組件 --> 
  8. <component :is="condition ? 'FooComponent' : 'BarComponent'"></component> 
  9.  
  10. <!-- 可以用來渲染原生 HTML 元素 --> 
  11. <component :is="href ? 'a' : 'span'"></component> 

2.1 綁定字符串類型

介紹完 component 內置組件,我們來舉個簡單的示例:

  1. <div id="app"
  2.    <button 
  3.       v-for="tab in tabs" 
  4.       :key="tab" 
  5.       @click="currentTab = 'tab-' + tab.toLowerCase()"
  6.       {{ tab }} 
  7.    </button> 
  8.    <component :is="currentTab"></component> 
  9. </div> 
  10. <script> 
  11.    const { createApp } = Vue 
  12.    const tabs = ['Home''My'
  13.    const app = createApp({ 
  14.      data() { 
  15.        return { 
  16.          tabs, 
  17.          currentTab: 'tab-' + tabs[0].toLowerCase() 
  18.        } 
  19.      }, 
  20.    }); 
  21.    app.component('tab-home', { 
  22.      template: `<div style="border: 1px solid;">Home component</div>` 
  23.    }) 
  24.    app.component('tab-my', { 
  25.      template: `<div style="border: 1px solid;">My component</div>` 
  26.    }) 
  27.    app.mount('#app'
  28. </script> 

在以上代碼中,我們通過 app.component 方法全局注冊了 tab-home 和 tab-my 2 個組件。此外,在模板中,我們使用了 component 內置組件,該組件的 is 屬性綁定了 data 對象的 currentTab 屬性,該屬性的類型是字符串。當用戶點擊 Tab 按鈕時,會動態更新 currentTab 的值,從而實現動態切換組件的功能。以上示例成功運行后的結果如下圖所示:

看到這里你會不會覺得 component 內置組件挺神奇的,感興趣的小伙伴繼續跟阿寶哥一起,來揭開它背后的秘密。下面我們利用 Vue 3 Template Explorer 在線工具,看一下 模板編譯的結果:

  1. const _Vue = Vue 
  2.  
  3. return function render(_ctx, _cache, $props, $setup, $data, $options) { 
  4.   with (_ctx) { 
  5.     const { resolveDynamicComponent: _resolveDynamicComponent, openBlock: _openBlock,  
  6.       createBlock: _createBlock } = _Vue 
  7.     return (_openBlock(), _createBlock(_resolveDynamicComponent(currentTab))) 
  8.   } 

通過觀察生成的渲染函數,我們發現了一個 resolveDynamicComponent 的函數,根據該函數的名稱,我們可以知道它用于解析動態組件,它被定義在 runtime-core/src/helpers/resolveAssets.ts 文件中,具體實現如下所示:

  1. // packages/runtime-core/src/helpers/resolveAssets.ts 
  2. export function resolveDynamicComponent(component: unknown): VNodeTypes { 
  3.   if (isString(component)) { 
  4.     return resolveAsset(COMPONENTS, component, false) || component 
  5.   } else { 
  6.     // invalid types will fallthrough to createVNode and raise warning 
  7.     return (component || NULL_DYNAMIC_COMPONENT) as any 
  8.   } 

在 resolveDynamicComponent 函數內部,若 component 參數是字符串類型,則會調用前面介紹的 resolveAsset 方法來解析組件:

  1. // packages/runtime-core/src/helpers/resolveAssets.ts 
  2. function resolveAsset( 
  3.   type: typeof COMPONENTS | typeof DIRECTIVES, 
  4.   name: string, 
  5.   warnMissing = true 
  6. ) { 
  7.   const instance = currentRenderingInstance || currentInstance 
  8.   if (instance) { 
  9.     const Component = instance.type 
  10.     // 省略大部分處理邏輯 
  11.     const res = 
  12.       // 局部注冊 
  13.       // check instance[type] first for components with mixin or extends. 
  14.       resolve(instance[type] || (Component as ComponentOptions)[type], name) || 
  15.       // 全局注冊 
  16.       resolve(instance.appContext[type], name
  17.     return res 
  18.   } 

對于前面的示例來說,組件是全局注冊的,所以解析過程中會從 app.context 上下文對象的 components 屬性中獲取對應的組件。當 currentTab 發生變化時,resolveAsset 函數就會返回不同的組件,從而實現動態組件的功能。

此外,如果 resolveAsset 函數獲取不到對應的組件,則會返回當前 component 參數的值。比如 resolveDynamicComponent('div') 將返回 'div' 字符串。

  1. // packages/runtime-core/src/helpers/resolveAssets.ts 
  2. export const NULL_DYNAMIC_COMPONENT = Symbol() 
  3.  
  4. export function resolveDynamicComponent(component: unknown): VNodeTypes { 
  5.   if (isString(component)) { 
  6.     return resolveAsset(COMPONENTS, component, false) || component 
  7.   } else { 
  8.     return (component || NULL_DYNAMIC_COMPONENT) as any 
  9.   } 

細心的小伙伴可能也注意到了,在 resolveDynamicComponent 函數內部,如果 component 參數非字符串類型,則會返回 component || NULL_DYNAMIC_COMPONENT 這行語句的執行結果,其中 NULL_DYNAMIC_COMPONENT 的值是一個 Symbol 對象。

2.2 綁定對象類型

了解完上述的內容之后,我們來重新實現一下前面動態 Tab 的功能:

  1. <div id="app"
  2.    <button 
  3.       v-for="tab in tabs" 
  4.       :key="tab" 
  5.       @click="currentTab = tab"
  6.      {{ tab.name }} 
  7.    </button> 
  8.    <component :is="currentTab.component"></component> 
  9. </div> 
  10. <script> 
  11.    const { createApp } = Vue 
  12.    const tabs = [ 
  13.      { 
  14.        name'Home'
  15.        component: { 
  16.          template: `<div style="border: 1px solid;">Home component</div>` 
  17.        } 
  18.      }, 
  19.      { 
  20.        name'My'
  21.        component: { 
  22.          template: `<div style="border: 1px solid;">My component</div>` 
  23.        } 
  24.    }] 
  25.    const app = createApp({ 
  26.      data() { 
  27.        return { 
  28.          tabs, 
  29.          currentTab: tabs[0] 
  30.        } 
  31.      }, 
  32.    }); 
  33.    app.mount('#app'
  34. </script> 

在以上示例中,component 內置組件的 is 屬性綁定了 currentTab 對象的 component 屬性,該屬性的值是一個對象。當用戶點擊 Tab 按鈕時,會動態更新 currentTab 的值,導致 currentTab.component 的值也發生變化,從而實現動態切換組件的功能。需要注意的是,每次切換的時候,都會重新創建動態組件。但在某些場景下,你會希望保持這些組件的狀態,以避免反復重渲染導致的性能問題。

對于這個問題,我們可以使用 Vue 3 的另一個內置組件 —— keep-alive,將動態組件包裹起來。比如:

  1. <keep-alive> 
  2.    <component :is="currentTab"></component> 
  3. </keep-alive>   

keep-alive 內置組件的主要作用是用于保留組件狀態或避免重新渲染,使用它包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。關于 keep-alive 組件的內部工作原理,阿寶哥后面會寫專門的文章來分析它,對它感興趣的小伙伴記得關注 Vue 3.0 進階 系列喲。

三、阿寶哥有話說

3.1 除了 component 內置組件外,還有哪些內置組件?

在 Vue 3 中除了本文介紹的 component 和 keep-alive 內置組件之外,還提供了 transition、transition-group 、slot 和 teleport 內置組件。

3.2 注冊全局組件與局部組件有什么區別?

注冊全局組件

  1. const { createApp, h } = Vue 
  2. const app = createApp({}); 
  3. app.component('component-a', { 
  4.   template: "<p>我是組件A</p>" 
  5. }); 

使用 app.component 方法注冊的全局的組件,被保存到 app 應用對象的上下文對象中。而通過組件對象 components 屬性注冊的局部組件是保存在組件實例中。

注冊局部組件

  1. const { createApp, h } = Vue 
  2. const app = createApp({}); 
  3. const componentA = () => h('div''我是組件A'); 
  4. app.component('component-b', { 
  5.   components: { 
  6.     'component-a': componentA 
  7.   }, 
  8.   template: `<div> 
  9.     我是組件B,內部使用了組件A 
  10.     <component-a></component-a>     
  11.   </div>` 
  12. }) 

解析全局注冊和局部注冊的組件

  1. // packages/runtime-core/src/helpers/resolveAssets.ts 
  2. function resolveAsset( 
  3.   type: typeof COMPONENTS | typeof DIRECTIVES, 
  4.   name: string, 
  5.   warnMissing = true 
  6. ) { 
  7.   const instance = currentRenderingInstance || currentInstance 
  8.   if (instance) { 
  9.     const Component = instance.type 
  10.     // 省略大部分處理邏輯 
  11.     const res = 
  12.       // 局部注冊 
  13.       // check instance[type] first for components with mixin or extends. 
  14.       resolve(instance[type] || (Component as ComponentOptions)[type], name) || 
  15.       // 全局注冊 
  16.       resolve(instance.appContext[type], name
  17.     return res 
  18.   } 

3.3 動態組件能否綁定其他屬性?

component 內置組件除了支持 is 綁定之外,也支持其他屬性綁定和事件綁定:

  1. <component :is="currentTab.component" :name="name" @click="sayHi"></component> 

這里阿寶哥使用 Vue 3 Template Explorer 這個在線工具,來編譯上述的模板:

  1. const _Vue = Vue 
  2. return function render(_ctx, _cache, $props, $setup, $data, $options) { 
  3.   with (_ctx) { 
  4.     const { resolveDynamicComponent: _resolveDynamicComponent,  
  5.       openBlock: _openBlock, createBlock: _createBlock } = _Vue 
  6.  
  7.     return (_openBlock(), _createBlock(_resolveDynamicComponent(currentTab.component), { 
  8.       namename
  9.       onClick: sayHi 
  10.     }, null, 8 /* PROPS */, ["name""onClick"])) 
  11.   } 

觀察以上的渲染函數可知,除了 is 綁定會被轉換為 _resolveDynamicComponent 函數調用之外,其他的屬性綁定都會被正常解析為 props 對象。

四、參考資源

Vue 3 官網 - 應用 API

Vue 3 官網 - 內置組件

 

責任編輯:武曉燕 來源: 全棧修仙之路
相關推薦

2021-02-26 05:19:20

Vue 3.0 VNode虛擬

2021-02-16 16:41:45

Vue項目指令

2021-02-19 23:07:02

Vue綁定組件

2021-02-28 20:41:18

Vue注入Angular

2021-02-18 08:19:21

Vue自定義Vue 3.0

2021-03-04 22:31:02

Vue進階函數

2021-03-09 22:29:46

Vue 響應式API

2021-03-08 00:08:29

Vue應用掛載

2020-09-16 06:12:30

Vue.js 3.0Suspense組件前端

2021-09-05 07:35:58

lifecycleAndroid組件原理

2020-09-28 15:48:37

開源技術 軟件

2010-05-11 16:22:40

2024-10-15 07:42:09

Vue動態加載

2020-10-13 08:24:31

Vue3.0系列

2020-04-22 14:15:32

Vue 3.0語法前端

2009-07-27 10:08:48

Java 7動態語言JVM

2025-01-22 13:05:58

2010-06-28 09:26:15

JDK 7Swing組件Java

2011-05-20 09:35:22

JDK7

2011-05-20 09:43:23

JDK7
點贊
收藏

51CTO技術棧公眾號

欧美手机在线观看| 久久久国产欧美| 香蕉av在线播放| 日日夜夜精品免费视频| 在线一区二区日韩| 免费人成视频在线播放| 国产亚洲成av人片在线观看| 2014亚洲片线观看视频免费| 成人a在线视频| 日韩熟女精品一区二区三区| 欧美一区电影| 日韩精品资源二区在线| 国产美女三级视频| 性爱视频在线播放| 国产婷婷色一区二区三区| 亚洲自拍偷拍色图| 亚洲第一网站在线观看| 午夜精品免费| 中文字幕亚洲激情| 亚洲av网址在线| 婷婷激情成人| 一道本成人在线| www.成年人视频| 69视频在线| 久久久电影一区二区三区| 91福利视频导航| 黄色一区二区视频| 国产日韩欧美一区| 久精品免费视频| 国产成人在线网址| 欧美精品momsxxx| 亚洲第一区中文99精品| 九一精品久久久| 国产在线|日韩| 欧美日韩亚洲成人| 国产freexxxx性播放麻豆| 黄色网页网址在线免费| 国产视频在线观看一区二区三区 | 亚洲免费av片| 国产艳妇疯狂做爰视频 | 高清电影在线观看免费| 国产精品乱人伦| 色就是色欧美| 日本一区二区三区在线观看视频| 福利电影一区二区三区| 成人免费大片黄在线播放| 一区二区三区麻豆| 久久午夜激情| 国产精品成人aaaaa网站| 亚洲免费黄色网址| 亚洲一区亚洲| 26uuu亚洲伊人春色| 久久高清免费视频| 激情视频一区二区三区| 欧美国产乱视频| 欧美精品一级片| 黄色在线成人| 国语自产精品视频在线看抢先版图片 | 日韩一区二区三区四区五区 | 午夜精品久久久久久久96蜜桃| 久久成人久久鬼色| 国产三级精品网站| 亚洲视频在线免费播放| 精品一区二区影视| 成人免费黄色网| 国产哺乳奶水91在线播放| 国产一区二区影院| 97久久天天综合色天天综合色hd| 国产露脸无套对白在线播放| 国产在线麻豆精品观看| 国产一区激情在线| 最新的欧美黄色| 麻豆一区在线观看| 亚洲色图国产| 久久久久久久久久久人体| 日本一级黄色大片| 男女精品网站| 国产精品免费看久久久香蕉| 亚洲天堂999| 国产一区二区导航在线播放| 国产精品国色综合久久| 日本一区高清| 中文字幕中文乱码欧美一区二区| 一级特黄妇女高潮| av男人的天堂在线观看| 色偷偷成人一区二区三区91| 97在线免费公开视频| 国产乱子精品一区二区在线观看| 91精品国产高清一区二区三区蜜臀| 国偷自产av一区二区三区麻豆| 老司机成人在线| 中文字幕欧美日韩精品| 久久久久久久久久久网| 亚洲免费影视| 91免费电影网站| 天天操天天干天天插| 国产精品视频观看| 欧妇女乱妇女乱视频| 性孕妇free特大另类| 欧美喷水一区二区| 欧美大喷水吹潮合集在线观看| heyzo久久| 欧美激情免费视频| 成年人晚上看的视频| 国产91精品露脸国语对白| 久久99精品久久久久久秒播放器 | 欧美激情一区二区三区四区| 男同互操gay射视频在线看| free性护士videos欧美| 欧美日韩电影在线| 久久一区二区电影| 欧美成人嫩草网站| 国产成人精品在线观看| 亚洲AV无码成人片在线观看| 国产欧美日韩久久| 国产3p露脸普通话对白| 国产日韩中文在线中文字幕| 亚洲视频在线免费观看| xxxx 国产| 国产剧情一区在线| 亚洲免费不卡| sis001欧美| 日韩欧美一二三四区| 手机看片国产日韩| 久久电影一区| 精品视频在线观看| 女囚岛在线观看| 欧美日韩中文字幕精品| 中文字幕丰满乱子伦无码专区| 黑人一区二区| 成人在线国产精品| 你懂的在线播放| 性久久久久久久久久久久| 丰满人妻一区二区三区53视频| 成人激情免费视频| 日本久久久久久久久| 欧美 日韩 人妻 高清 中文| 亚洲视频综合在线| 亚洲这里只有精品| 欧美一区2区| 国产精品久久婷婷六月丁香| 巨骚激情综合| 日本精品一区二区三区四区的功能| 久久福利小视频| 亚洲国产片色| www.成人av.com| 欧洲中文在线| 精品国产免费一区二区三区四区 | 一本一道久久综合狠狠老精东影业| 亚洲xxxxx| 国产激情在线视频| 91精品国产黑色紧身裤美女| 久久中文免费视频| 国产福利精品一区二区| 免费观看亚洲视频| 亚洲超碰在线观看| 欧美日本高清视频| 国产成人无码www免费视频播放| 亚洲精品菠萝久久久久久久| 欧美老女人bb| 日韩午夜黄色| 你懂的网址一区二区三区| 国产精品伦子伦| 国内精品久久久久久99蜜桃| 国产91在线播放精品91| 国内在线精品| 欧美精品一二三区| 久久精品黄色片| k8久久久一区二区三区| 国产又黄又大又粗视频| 国产一区二区精品福利地址| 国产精品久久久久久久久借妻| 亚洲精品承认| 日韩精品一区二区三区中文不卡| 国产一级一级片| 久久综合久久99| 爱爱爱爱免费视频| 激情久久一区| 色一情一区二区三区四区| 伊人久久大香伊蕉在人线观看热v 伊人久久大香线蕉综合影院首页 伊人久久大香 | 中文天堂在线播放| 亚洲人成网站精品片在线观看| 免费在线观看日韩av| 国产精品夜夜夜| 一道精品一区二区三区| 2020最新国产精品| 欧美与欧洲交xxxx免费观看 | 亚洲涩涩av| 国产精品爽爽爽爽爽爽在线观看| 老司机在线视频二区| 日韩欧美色电影| 欧产日产国产69| 日韩毛片视频在线看| 亚洲av无码专区在线播放中文| 亚洲欧美日韩一区在线观看| 亚洲电影一二三区| 91综合精品国产丝袜长腿久久| 欧美最顶级丰满的aⅴ艳星| 天天影视久久综合| 亚洲黄页网在线观看| www.亚洲激情| 亚洲成人av资源| 毛片视频免费播放| 97精品久久久久中文字幕| 国内外成人免费在线视频| 国内精品福利| 亚洲精品乱码视频| 偷窥自拍亚洲色图精选| 亚洲影视中文字幕| 97久久网站| 欧美资源在线观看| 免费在线看电影| 中文字幕自拍vr一区二区三区| 欧性猛交ⅹxxx乱大交| 欧美日韩美女一区二区| 免费观看一区二区三区毛片| 亚洲免费看黄网站| 先锋影音av在线| 99国内精品久久| 免费黄视频在线观看| 蜜臀国产一区二区三区在线播放| 欧美精品卡一卡二| 一精品久久久| 裸体大乳女做爰69| 日韩精品永久网址| 日韩av免费电影| 亚洲天堂日韩在线| 国产一区二区三区高清| 亚洲精品一区二区三区中文字幕| 国产精品一区二区久久久久| 欧美aa视频| 人体精品一二三区| 国产在线美女| 国外成人在线直播| 爱情岛亚洲播放路线| 久久999免费视频| 国产原厂视频在线观看| 日韩中文字幕在线观看| 在线观看美女网站大全免费| 亚洲色图综合网| 欧美日韩伦理片| 亚洲男人av电影| 撸视在线观看免费视频| 亚洲欧洲美洲在线综合| 天天射天天色天天干| 亚洲成人久久一区| 欧美一区二不卡视频| 亚洲国产精品推荐| 天天干天天做天天操| 日韩精品视频在线观看网址| 香港一级纯黄大片| 亚洲欧美在线一区二区| 免费黄色片在线观看| 亚洲天堂久久av| 亚洲1卡2卡3卡4卡乱码精品| 中文字幕精品国产| 国产在线观看a视频| 久久97久久97精品免视看| 黄页网站在线观看免费| 国内揄拍国内精品少妇国语| 久久男人av资源站| 国产激情999| 深夜福利亚洲| 99re在线视频观看| 女同久久另类99精品国产| 久久精品中文字幕一区二区三区| 天美av一区二区三区久久| 欧美日本韩国国产| 精品视频99| 欧美少妇一级片| 伊人天天综合| 久久精品.com| 老司机精品视频导航| 免费人成视频在线播放| 99热99精品| jizz18女人高潮| 亚洲免费av在线| 国产精品久久久久久久妇| 日本道精品一区二区三区| 91精品国产乱码久久久久| 日韩精品一区二区三区视频| 深夜福利在线看| 色偷偷88888欧美精品久久久| a视频在线观看免费| …久久精品99久久香蕉国产| 97欧美成人| 国产欧美日韩综合精品二区| 国产成人手机高清在线观看网站| 黄色免费高清视频| 国产欧美日韩一区二区三区在线| 黄色在线视频网| 成人免费毛片嘿嘿连载视频| 国产aⅴ激情无码久久久无码| 综合久久综合久久| 久久国产视频精品| 欧美一区二区大片| 免费a级毛片在线观看| 久久av资源网站| 写真福利精品福利在线观看| 99久久精品无码一区二区毛片| 国产成人高清| 国产毛片久久久久久国产毛片| 日本va欧美va欧美va精品| 最新中文字幕日本| 欧美国产丝袜视频| 日韩精品成人在线| 69久久99精品久久久久婷婷| 四虎电影院在线观看| 久久成年人免费电影| 欧美在线va视频| 精品欧美国产一区二区三区不卡| 四虎成人精品永久免费av九九| 欧美在线观看www| 国产99久久久久| 日韩在线不卡av| 91极品视觉盛宴| 婷婷在线观看视频| 久久99久久久久久久噜噜| 国产一区二区主播在线| 国内一区二区三区在线视频| 欧美.日韩.国产.一区.二区| 亚洲激情在线观看视频| 91片在线免费观看| 久久9999久久免费精品国产| 制服.丝袜.亚洲.中文.综合| 成人高清网站| 国产91在线视频| 欧美日韩导航| 国产日本在线播放| 国产成人免费在线观看不卡| 欧美h片在线观看| 欧美三级韩国三级日本三斤| 九色在线免费| 欧洲成人在线观看| 婷婷精品在线| www国产黄色| 久久综合国产精品| 天天综合网入口| 日韩成人在线视频观看| 51精品在线| 激情一区二区三区| 国产欧美日韩一区二区三区在线| 亚洲精品第二页| 亚洲地区一二三色| 色哟哟中文字幕| 97精品视频在线观看| 激情小说亚洲色图| 国产原创popny丨九色| 不卡大黄网站免费看| 日韩手机在线观看| 精品亚洲男同gayvideo网站| 特黄毛片在线观看| 欧美日韩天天操| 日本sm残虐另类| 99热这里只有精品4| 欧美久久一二三四区| 黄色的网站在线观看| 99热在线播放| 亚洲激情不卡| 欧美狂猛xxxxx乱大交3| 欧洲一区二区av| 青青影院在线观看| 91精品国产一区二区三区动漫 | 久久亚洲中文字幕无码| aaa欧美日韩| 无码人妻精品一区二区三区不卡| 亚洲欧洲一区二区三区在线观看| 亚洲精品粉嫩美女一区| 亚洲一区三区在线观看| 国产酒店精品激情| 久久不卡免费视频| 尤物yw午夜国产精品视频明星| 高清在线一区| 欧美日韩视频免费| 久久蜜臀精品av| 6—12呦国产精品| 高清一区二区三区四区五区| 最近国产精品视频| 夜夜夜夜夜夜操| 午夜精品久久久久久| 久久电影中文字幕| 91社区国产高清| 中文欧美日韩| 国产又粗又长又黄的视频| 日韩三级视频中文字幕| 成人免费网站视频| 最近免费观看高清韩国日本大全| 成人ar影院免费观看视频| 91麻豆精品在线| 久久久久国产精品一区| 中文有码一区| 韩国三级丰满少妇高潮| 欧美性猛交xxxx黑人| 免费网站黄在线观看| 国产一区二区三区奇米久涩| 蜜桃久久精品一区二区| 久久久精品一区二区涩爱| 国产一区二区三区在线视频| 中文字幕一区二区三区四区久久 | 精品精品视频|