亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

淺析vue-router原理

2019-11-19 12:40:12
字體:
來源:轉載
供稿:網友

近期被問到一個問題,在你們項目中使用的是Vue的SPA(單頁面)還是Vue的多頁面設計?

這篇文章主要圍繞Vue的SPA單頁面設計展開。 關于如何展開Vue多頁面設計請點擊查看。

vue-router是什么?

首先我們需要知道vue-router是什么,它是干什么的?

這里指的路由并不是指我們平時所說的硬件路由器,這里的路由就是SPA(單頁應用)的路徑管理器。 換句話說,vue-router就是WebApp的鏈接路徑管理系統。

vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,適合用于構建單頁面應用。

那與傳統的頁面跳轉有什么區別呢?

1.vue的單頁面應用是基于路由和組件的,路由用于設定訪問路徑,并將路徑和組件映射起來。

2.傳統的頁面應用,是用一些超鏈接來實現頁面切換和跳轉的。

在vue-router單頁面應用中,則是路徑之間的切換,也就是組件的切換。路由模塊的本質 就是建立起url和頁面之間的映射關系。

至于為啥不能用a標簽,這是因為用Vue做的都是單頁應用,就相當于只有一個主的index.html頁面,所以你寫的標簽是不起作用的,必須使用vue-router來進行管理。

vue-router實現原理

SPA(single page application):單一頁面應用程序,有且只有一個完整的頁面;當它在加載頁面的時候,不會加載整個頁面的內容,而只更新某個指定的容器中內容。

單頁面應用(SPA)的核心之一是:

1.更新視圖而不重新請求頁面;

2.vue-router在實現單頁面前端路由時,提供了三種方式:Hash模式、History模式、abstract模式,根據mode參數來決定采用哪一種方式。

路由模式

vue-router 提供了三種運行模式:

● hash: 使用 URL hash 值來作路由。默認模式。

● history: 依賴 HTML5 History API 和服務器配置。查看 HTML5 History 模式。

● abstract: 支持所有 JavaScript 運行環境,如 Node.js 服務器端。

Hash模式

vue-router 默認模式是 hash 模式 ―― 使用 URL 的 hash 來模擬一個完整的 URL,當 URL 改變時,頁面不會去重新加載。

hash(#)是URL 的錨點,代表的是網頁中的一個位置,單單改變#后的部分(/#/..),瀏覽器只會加載相應位置的內容,不會重新加載網頁,也就是說 #是用來指導瀏覽器動作的,對服務器端完全無用,HTTP請求中不包括#;同時每一次改變#后的部分,都會在瀏覽器的訪問歷史中增加一個記錄,使用”后退”按鈕,就可以回到上一個位置; 所以說Hash模式通過錨點值的改變,根據不同的值,渲染指定DOM位置的不同數據 。

History模式

HTML5 History API提供了一種功能,能讓開發人員在不刷新整個頁面的情況下修改站點的URL,就是利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面;

由于hash模式會在url中自帶#,如果不想要很丑的 hash,我們可以用路由的 history 模式,只需要在配置路由規則時,加入"mode: 'history'",這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面。

//main.js文件中const router = new VueRouter({ mode: 'history', routes: [...]})

當使用 history 模式時,URL 就像正常的 url,例如 yoursite.com/user/id,比較好… 不過這種模式要玩好,還需要后臺配置支持。因為我們的應用是個單頁客戶端應用,如果后臺沒有正確的配置,當用戶在瀏覽器直接訪問

所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。

export const routes = [  {path: "/", name: "homeLink", component:Home} {path: "/register", name: "registerLink", component: Register}, {path: "/login", name: "loginLink", component: Login}, {path: "*", redirect: "/"}] 

此處就設置如果URL輸入錯誤或者是URL 匹配不到任何靜態資源,就自動跳到到Home頁面。

abstract模式

abstract模式是使用一個不依賴于瀏覽器的瀏覽歷史虛擬管理后端。

根據平臺差異可以看出,在 Weex 環境中只支持使用 abstract 模式。 不過,vue-router 自身會對環境做校驗,如果發現沒有瀏覽器的 API,vue-router 會自動強制進入 abstract 模式,所以 在使用 vue-router 時只要不寫 mode 配置即可,默認會在瀏覽器環境中使用 hash 模式,在移動端原生環境中使用 abstract 模式。 (當然,你也可以明確指定在所有情況下都使用 abstract 模式)

vue-router使用方式

1:下載npm i vue-router -S

**2:在main.js中引入 ** import VueRouter from 'vue-router';

3:安裝插件Vue.use(VueRouter);

4:創建路由對象并配置路由規則

let router = new VueRouter({routes:[{path:'/home',component:Home}]});

5:將其路由對象傳遞給Vue的實例,options中加入 router:router

6:在app.vue中留坑

<router-view></router-view>

具體實現請看如下代碼:

//main.js文件中引入import Vue from 'vue';import VueRouter from 'vue-router';//主體import App from './components/app.vue';import index from './components/index.vue'//安裝插件Vue.use(VueRouter); //掛載屬性//創建路由對象并配置路由規則let router = new VueRouter({  routes: [    //一個個對象    { path: '/index', component: index }  ]});//new Vue 啟動new Vue({  el: '#app',  //讓vue知道我們的路由規則  router: router, //可以簡寫router  render: c => c(App),})

最后記得在在app.vue中“留坑”

//app.vue中<template>  <div>    <!-- 留坑,非常重要 -->    <router-view></router-view>  </div></template><script>  export default {    data(){      return {}    }  }</script>

vue-router源碼分析

我們先來看看vue的實現路徑。

在入口文件中需要實例化一個 VueRouter 的實例對象 ,然后將其傳入 Vue 實例的 options 中。

export default class VueRouter { static install: () => void; static version: string; app: any; apps: Array<any>; ready: boolean; readyCbs: Array<Function>; options: RouterOptions; mode: string; history: HashHistory | HTML5History | AbstractHistory; matcher: Matcher; fallback: boolean; beforeHooks: Array<?NavigationGuard>; resolveHooks: Array<?NavigationGuard>; afterHooks: Array<?AfterNavigationHook>; constructor (options: RouterOptions = {}) {  this.app = null  this.apps = []  this.options = options  this.beforeHooks = []  this.resolveHooks = []  this.afterHooks = []  // 創建 matcher 匹配函數  this.matcher = createMatcher(options.routes || [], this)  // 根據 mode 實例化具體的 History,默認為'hash'模式  let mode = options.mode || 'hash'  // 通過 supportsPushState 判斷瀏覽器是否支持'history'模式  // 如果設置的是'history'但是如果瀏覽器不支持的話,'history'模式會退回到'hash'模式  // fallback 是當瀏覽器不支持 history.pushState 控制路由是否應該回退到 hash 模式。默認值為 true。  this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false  if (this.fallback) {   mode = 'hash'  }  // 不在瀏覽器內部的話,就會變成'abstract'模式  if (!inBrowser) {   mode = 'abstract'  }  this.mode = mode   // 根據不同模式選擇實例化對應的 History 類  switch (mode) {   case 'history':    this.history = new HTML5History(this, options.base)    break   case 'hash':    this.history = new HashHistory(this, options.base, this.fallback)    break   case 'abstract':    this.history = new AbstractHistory(this, options.base)    break   default:    if (process.env.NODE_ENV !== 'production') {     assert(false, `invalid mode: ${mode}`)    }  } } match (  raw: RawLocation,  current?: Route,  redirectedFrom?: Location ): Route {  return this.matcher.match(raw, current, redirectedFrom) } get currentRoute (): ?Route {  return this.history && this.history.current } init (app: any /* Vue component instance */) {  process.env.NODE_ENV !== 'production' && assert(   install.installed,   `not installed. Make sure to call /`Vue.use(VueRouter)/` ` +   `before creating root instance.`  )  this.apps.push(app)  // main app already initialized.  if (this.app) {   return  }  this.app = app  const history = this.history  // 根據history的類別執行相應的初始化操作和監聽  if (history instanceof HTML5History) {   history.transitionTo(history.getCurrentLocation())  } else if (history instanceof HashHistory) {   const setupHashListener = () => {    history.setupListeners()   }   history.transitionTo(    history.getCurrentLocation(),    setupHashListener,    setupHashListener   )  }  history.listen(route => {   this.apps.forEach((app) => {    app._route = route   })  }) } // 路由跳轉之前 beforeEach (fn: Function): Function {  return registerHook(this.beforeHooks, fn) } // 路由導航被確認之間前 beforeResolve (fn: Function): Function {  return registerHook(this.resolveHooks, fn) } // 路由跳轉之后 afterEach (fn: Function): Function {  return registerHook(this.afterHooks, fn) } // 第一次路由跳轉完成時被調用的回調函數 onReady (cb: Function, errorCb?: Function) {  this.history.onReady(cb, errorCb) } // 路由報錯 onError (errorCb: Function) {  this.history.onError(errorCb) } // 路由添加,這個方法會向history棧添加一個記錄,點擊后退會返回到上一個頁面。 push (location: RawLocation, onComplete?: Function, onAbort?: Function) {  this.history.push(location, onComplete, onAbort) } // 這個方法不會向history里面添加新的記錄,點擊返回,會跳轉到上上一個頁面。上一個記錄是不存在的。 replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {  this.history.replace(location, onComplete, onAbort) } // 相對于當前頁面向前或向后跳轉多少個頁面,類似 window.history.go(n)。n可為正數可為負數。正數返回上一個頁面 go (n: number) {  this.history.go(n) } // 后退到上一個頁面 back () {  this.go(-1) } // 前進到下一個頁面 forward () {  this.go(1) } getMatchedComponents (to?: RawLocation | Route): Array<any> {  const route: any = to   ? to.matched    ? to    : this.resolve(to).route   : this.currentRoute  if (!route) {   return []  }  return [].concat.apply([], route.matched.map(m => {   return Object.keys(m.components).map(key => {    return m.components[key]   })  })) } resolve (  to: RawLocation,  current?: Route,  append?: boolean ): {  location: Location,  route: Route,  href: string,  // for backwards compat  normalizedTo: Location,  resolved: Route } {  const location = normalizeLocation(   to,   current || this.history.current,   append,   this  )  const route = this.match(location, current)  const fullPath = route.redirectedFrom || route.fullPath  const base = this.history.base  const href = createHref(base, fullPath, this.mode)  return {   location,   route,   href,   // for backwards compat   normalizedTo: location,   resolved: route  } } addRoutes (routes: Array<RouteConfig>) {  this.matcher.addRoutes(routes)  if (this.history.current !== START) {   this.history.transitionTo(this.history.getCurrentLocation())  } }}

HashHistory

• hash雖然出現在url中,但不會被包括在http請求中,它是用來指導瀏覽器動作的,對服務器端沒影響,因此,改變hash不會重新加載頁面。

• 可以為hash的改變添加監聽事件:

window.addEventListener("hashchange",funcRef,false)

• 每一次改變hash(window.location.hash),都會在瀏覽器訪問歷史中增加一個記錄。

export class HashHistory extends History { constructor (router: Router, base: ?string, fallback: boolean) {  super(router, base)  // check history fallback deeplinking  // 如果是從history模式降級來的,需要做降級檢查  if (fallback && checkFallback(this.base)) {  // 如果降級且做了降級處理,則返回   return  }  ensureSlash() } .......function checkFallback (base) { const location = getLocation(base) // 得到除去base的真正的 location 值 if (!/^//#/.test(location)) { // 如果此時地址不是以 /# 開頭的 // 需要做一次降級處理,降為 hash 模式下應有的 /# 開頭  window.location.replace(   cleanPath(base + '/#' + location)  )  return true }}function ensureSlash (): boolean {// 得到 hash 值 const path = getHash() if (path.charAt(0) === '/') {  // 如果是以 / 開頭的,直接返回即可  return true } // 不是的話,需要手動保證一次 替換 hash 值 replaceHash('/' + path) return false}export function getHash (): string { // We can't use window.location.hash here because it's not // consistent across browsers - Firefox will pre-decode it! // 因為兼容性的問題,這里沒有直接使用 window.location.hash // 因為 Firefox decode hash 值 const href = window.location.href const index = href.indexOf('#') return index === -1 ? '' : decodeURI(href.slice(index + 1))}// 得到hash之前的url地址function getUrl (path) { const href = window.location.href const i = href.indexOf('#') const base = i >= 0 ? href.slice(0, i) : href return `${base}#${path}`}// 添加一個hashfunction pushHash (path) { if (supportsPushState) {  pushState(getUrl(path)) } else {  window.location.hash = path }}// 替代hashfunction replaceHash (path) { if (supportsPushState) {  replaceState(getUrl(path)) } else {  window.location.replace(getUrl(path)) }}

hash的改變會自動添加到瀏覽器的訪問歷史記錄中。 那么視圖的更新是怎么實現的呢,看下 transitionTo()方法:

transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {  const route = this.router.match(location, this.current) //找到匹配路由  this.confirmTransition(route, () => { //確認是否轉化   this.updateRoute(route) //更新route   onComplete && onComplete(route)   this.ensureURL()   // fire ready cbs once   if (!this.ready) {    this.ready = true    this.readyCbs.forEach(cb => { cb(route) })   }  }, err => {   if (onAbort) {    onAbort(err)   }   if (err && !this.ready) {    this.ready = true    this.readyErrorCbs.forEach(cb => { cb(err) })   }  }) } //更新路由updateRoute (route: Route) {  const prev = this.current // 跳轉前路由  this.current = route // 裝備跳轉路由  this.cb && this.cb(route) // 回調函數,這一步很重要,這個回調函數在index文件中注冊,會更新被劫持的數據 _router  this.router.afterHooks.forEach(hook => {   hook && hook(route, prev)  }) }}pushStateexport function pushState (url?: string, replace?: boolean) { saveScrollPosition() // try...catch the pushState call to get around Safari // DOM Exception 18 where it limits to 100 pushState calls // 加了 try...catch 是因為 Safari 有調用 pushState 100 次限制 // 一旦達到就會拋出 DOM Exception 18 錯誤 const history = window.history try {  if (replace) {  // replace 的話 key 還是當前的 key 沒必要生成新的   history.replaceState({ key: _key }, '', url)  } else {  // 重新生成 key   _key = genKey()    // 帶入新的 key 值   history.pushState({ key: _key }, '', url)  } } catch (e) { // 達到限制了 則重新指定新的地址  window.location[replace ? 'replace' : 'assign'](url) }}replaceState// 直接調用 pushState 傳入 replace 為 trueexport function replaceState (url?: string) { pushState(url, true)}

pushState和replaceState兩種方法的共同特點:當調用他們修改瀏覽器歷史棧后,雖然當前url改變了,但瀏覽器不會立即發送請求該url,這就為單頁應用前端路由,更新視圖但不重新請求頁面提供了基礎。

supportsPushStateexport const supportsPushState = inBrowser && (function () { const ua = window.navigator.userAgent if (  (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&  ua.indexOf('Mobile Safari') !== -1 &&  ua.indexOf('Chrome') === -1 &&  ua.indexOf('Windows Phone') === -1 ) {  return false } return window.history && 'pushState' in window.history})()

其實所謂響應式屬性,即當_route值改變時,會自動調用Vue實例的render()方法,更新視圖。 $router.push()-->HashHistory.push()-->History.transitionTo()-->History.updateRoute()-->{app._route=route}-->vm.render()

監聽地址欄

在瀏覽器中,用戶可以直接在瀏覽器地址欄中輸入改變路由,因此還需要監聽瀏覽器地址欄中路由的變化 ,并具有與通過代碼調用相同的響應行為,在HashHistory中這一功能通過setupListeners監聽hashchange實現:

setupListeners () {  window.addEventListener('hashchange', () => {    if (!ensureSlash()) {      return    }    this.transitionTo(getHash(), route => {      replaceHash(route.fullPath)    })  })}

HTML5History

History interface是瀏覽器歷史記錄棧提供的接口,通過back(),forward(),go()等方法,我們可以讀取瀏覽器歷史記錄棧的信息,進行各種跳轉操作。

export class HTML5History extends History { constructor (router: Router, base: ?string) {  super(router, base)  const expectScroll = router.options.scrollBehavior //指回滾方式  const supportsScroll = supportsPushState && expectScroll  if (supportsScroll) {   setupScroll()  }  const initLocation = getLocation(this.base)  //監控popstate事件  window.addEventListener('popstate', e => {   const current = this.current   // Avoiding first `popstate` event dispatched in some browsers but first   // history route not updated since async guard at the same time.   // 避免在某些瀏覽器中首次發出“popstate”事件   // 由于同一時間異步監聽,history路由沒有同時更新。   const location = getLocation(this.base)   if (this.current === START && location === initLocation) {    return   }   this.transitionTo(location, route => {    if (supportsScroll) {     handleScroll(router, route, current, true)    }   })  }) }

hash模式僅改變hash部分的內容,而hash部分是不會包含在http請求中的(hash帶#):

oursite.com/#/user/id //如請求,只會發送http://oursite.com/

所以hash模式下遇到根據url請求頁面不會有問題

而history模式則將url修改的就和正常請求后端的url一樣(history不帶#)

oursite.com/user/id

如果這種向后端發送請求的話,后端沒有配置對應/user/id的get路由處理,會返回404錯誤。

官方推薦的解決辦法是在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。同時這么做以后,服務器就不再返回 404 錯誤頁面,因為對于所有路徑都會返回 index.html 文件。為了避免這種情況,在 Vue 應用里面覆蓋所有的路由情況,然后在給出一個 404 頁面?;蛘?,如果是用 Node.js 作后臺,可以使用服務端的路由來匹配 URL,當沒有匹配到路由的時候返回 404,從而實現 fallback。

兩種模式比較

一般的需求場景中,hash模式與history模式是差不多的,根據MDN的介紹,調用history.pushState()相比于直接修改hash主要有以下優勢:

• pushState設置的新url可以是與當前url同源的任意url,而hash只可修改#后面的部分,故只可設置與當前同文檔的url

• pushState設置的新url可以與當前url一模一樣,這樣也會把記錄添加到棧中,而hash設置的新值必須與原來不一樣才會觸發記錄添加到棧中

• pushState通過stateObject可以添加任意類型的數據記錄中,而hash只可添加短字符串 pushState可額外設置title屬性供后續使用

AbstractHistory

'abstract'模式,不涉及和瀏覽器地址的相關記錄,流程跟'HashHistory'是一樣的,其原理是通過數組模擬瀏覽器歷史記錄棧的功能

//abstract.js實現,這里通過棧的數據結構來模擬路由路徑export class AbstractHistory extends History { index: number; stack: Array<Route>; constructor (router: Router, base: ?string) {  super(router, base)  this.stack = []  this.index = -1 }  // 對于 go 的模擬 go (n: number) {  // 新的歷史記錄位置  const targetIndex = this.index + n  // 小于或大于超出則返回  if (targetIndex < 0 || targetIndex >= this.stack.length) {   return  }  // 取得新的 route 對象  // 因為是和瀏覽器無關的 這里得到的一定是已經訪問過的  const route = this.stack[targetIndex]  // 所以這里直接調用 confirmTransition 了  // 而不是調用 transitionTo 還要走一遍 match 邏輯  this.confirmTransition(route, () => {   this.index = targetIndex   this.updateRoute(route)  }) }//確認是否轉化路由 confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {  const current = this.current  const abort = err => {   if (isError(err)) {    if (this.errorCbs.length) {     this.errorCbs.forEach(cb => { cb(err) })    } else {     warn(false, 'uncaught error during route navigation:')     console.error(err)    }   }   onAbort && onAbort(err)  }  //判斷如果前后是同一個路由,不進行操作  if (   isSameRoute(route, current) &&   route.matched.length === current.matched.length  ) {   this.ensureURL()   return abort()  }  //下面是各類鉤子函數的處理  //*********************  }) }

看到這里你已經對vue-router的路由基本掌握的差不多了,要是喜歡看源碼可以 點擊查 看

要是喜歡可以給我一個star,github

總結

以上所述是小編給大家介紹的vue-router原理淺析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲成在人线av| 琪琪亚洲精品午夜在线| 性欧美激情精品| 欧美精品videosex性欧美| 精品五月天久久| 国产91成人video| 亚洲在线观看视频网站| 亚洲国产欧美日韩精品| 欧美插天视频在线播放| 欧美高清理论片| 狠狠躁18三区二区一区| 日韩高清中文字幕| www.欧美视频| 97欧美精品一区二区三区| 欧美巨猛xxxx猛交黑人97人| 亚洲精品一区二三区不卡| 国产啪精品视频网站| 精品国产一区二区在线| 搡老女人一区二区三区视频tv| 92看片淫黄大片看国产片| 亚洲精品美女在线观看| 日韩高清有码在线| 国产精品久久久久7777婷婷| 在线精品国产欧美| 性欧美视频videos6一9| 麻豆精品精华液| 日韩亚洲第一页| 国产一级揄自揄精品视频| 国产精品毛片a∨一区二区三区|国| 亚洲一区中文字幕在线观看| 久久久之久亚州精品露出| 91精品国产网站| 中日韩午夜理伦电影免费| 精品久久久国产精品999| 中文字幕成人精品久久不卡| 九九热在线精品视频| 亚洲无限乱码一二三四麻| 91免费看国产| 91免费精品国偷自产在线| 欧美一级淫片aaaaaaa视频| 欧美日韩视频在线| 欧美理论电影在线播放| 亚洲成**性毛茸茸| 国外色69视频在线观看| 日韩欧美国产激情| 日韩黄色av网站| 日本一区二区三区在线播放| 亚洲精品综合精品自拍| 国产成人啪精品视频免费网| 国产香蕉一区二区三区在线视频| 国产亚洲一区精品| 国产精品视频网| 欧美激情2020午夜免费观看| 亚洲精品影视在线观看| 色哟哟网站入口亚洲精品| 在线亚洲国产精品网| 日韩综合视频在线观看| 欧美精品电影免费在线观看| 亚洲国产精品va在线看黑人| 国产精品视频不卡| 亚洲va欧美va在线观看| 亚洲成色999久久网站| 亚洲国产成人在线播放| 成人黄色免费网站在线观看| 国内精品美女av在线播放| 中文字幕欧美在线| 色偷偷88888欧美精品久久久| 国产精品久久国产精品99gif| 欧美激情第1页| 国产成人在线亚洲欧美| 欧美电影免费观看高清完整| 91在线直播亚洲| 亚洲欧美日韩一区在线| 亚洲级视频在线观看免费1级| 日韩一区在线视频| 亚洲曰本av电影| 亚洲精品xxx| 亚洲色图在线观看| 国产69精品99久久久久久宅男| 992tv在线成人免费观看| 亚洲精品国产精品乱码不99按摩| 亚洲三级av在线| 57pao成人永久免费视频| 欧美午夜精品久久久久久浪潮| 国产精品久久久久久超碰| 国产日韩欧美中文在线播放| 俺去了亚洲欧美日韩| 黑丝美女久久久| 欧美黑人巨大精品一区二区| 欧美激情综合色综合啪啪五月| 久久精品电影网| 国产+人+亚洲| 欧美成人免费全部观看天天性色| 国产成人精品在线视频| 亚洲欧美福利视频| 欧美日韩国产中字| 7777精品视频| 91人人爽人人爽人人精88v| 91久久综合亚洲鲁鲁五月天| 久久久久久久久综合| 国产亚洲欧洲在线| 国产精品国产三级国产aⅴ浪潮| 亚洲精品中文字幕av| 日韩激情av在线免费观看| 亚洲成人aaa| 国产精品久久久av久久久| 亚洲天堂男人的天堂| 亚洲社区在线观看| 欧美夫妻性生活视频| 98视频在线噜噜噜国产| 国产这里只有精品| 亚洲精品一区二区久| 久久亚洲电影天堂| 亚洲精品一区久久久久久| 国产欧美 在线欧美| 免费av一区二区| 亚洲一区二区三区香蕉| 91社影院在线观看| 在线播放国产一区中文字幕剧情欧美| 国产乱肥老妇国产一区二| 欧美极品少妇xxxxⅹ免费视频| 成人国产精品久久久久久亚洲| 欧美人在线观看| 日韩成人小视频| 综合国产在线观看| 亚洲视频在线免费观看| 91亚洲精品一区二区| 中文字幕精品网| 精品国产欧美一区二区三区成人| 福利二区91精品bt7086| 成人激情免费在线| 97av在线播放| 动漫精品一区二区| 中文字幕日本精品| 亚洲第一福利视频| 亚洲一区亚洲二区亚洲三区| 欧美超级免费视 在线| 日韩国产精品亚洲а∨天堂免| 日韩av男人的天堂| 欧美精品18videos性欧| 亚洲最大成人免费视频| 一个人www欧美| 国产精品久久久久久av福利软件| 视频在线一区二区| 亚洲色图狂野欧美| 日韩视频免费中文字幕| 国产精品久久久久久久午夜| 国产91热爆ts人妖在线| 国产精品无av码在线观看| 色综合久久中文字幕综合网小说| 久久久av一区| 国产丝袜高跟一区| 国产69精品久久久| 亚洲最大在线视频| 亚洲精品suv精品一区二区| 日韩av影视在线| 国产精品久久久久久久久久免费| 亚洲aa在线观看| 日本成人黄色片| 亚洲国产又黄又爽女人高潮的| 久久久噜噜噜久久中文字免| 欧美一区二区色| 成人在线一区二区| 欧美肥老妇视频|