国产无遮挡裸体免费直播视频,久久精品国产蜜臀av,动漫在线视频一区二区,欧亚日韩一区二区三区,久艹在线 免费视频,国产精品美女网站免费,正在播放 97超级视频在线观看,斗破苍穹年番在线观看免费,51最新乱码中文字幕

Vue3源碼通過(guò)render?patch?了解diff

 更新時(shí)間:2022年11月03日 10:51:46   作者:ChrisLey  
這篇文章主要為大家介紹了Vue3源碼系列通過(guò)render及patch了解diff原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

上一篇中,我們理清了createApp走的流程,最后通過(guò)createAppAPI創(chuàng)建了app。雖然app上的各種屬性和方法也都已經(jīng)有所了解,但其中的mountunmount方法,都是通過(guò)調(diào)用render函數(shù)來(lái)完成的。盡管我們很好奇render函數(shù)的故事,可是baseCreateRenderer函數(shù)有2000+行,基本都和render相關(guān),因此拆解到本文里敘述,以下方法都定義在baseCreateRenderer函數(shù)中。

render

render也不神秘了,畢竟在上一篇文章中露過(guò)面,當(dāng)然這里也順帶提一下 baseCreateRenderer從參數(shù)options中解構(gòu)的一些方法,基本都是些增刪改查、復(fù)制節(jié)點(diǎn)的功能,見(jiàn)名知義了。主要看看render,接收vnode、containerisSvg三個(gè)參數(shù)。調(diào)用unmount卸載或者調(diào)用patch進(jìn)行節(jié)點(diǎn)比較從而繼續(xù)下一步。

  • 判斷vnode是否為null。如果對(duì)上一篇文章還有印象,那么就會(huì)知道,相當(dāng)于是判斷調(diào)用的是app.mount還是app.unmount方法,因?yàn)?code>app.unmount方法傳入的vnode就是null。那么這里對(duì)應(yīng)的就是在app.unmount里使用unmount函數(shù)來(lái)卸載;而在app.mount里進(jìn)行patch比較。
  • 調(diào)用flushPostFlushCbs(),其中的單詞Post的含義,看過(guò)第一篇講解watch的同學(xué)也許能猜出來(lái),表示執(zhí)行時(shí)機(jī)是在組件更新后。這個(gè)函數(shù)便是執(zhí)行組件更新后的一些回調(diào)。
  • vnode掛到container上,即舊的虛擬DOM
const {
  insert: hostInsert,
  remove: hostRemove,
  patchProp: hostPatchProp,
  createElement: hostCreateElement,
  createText: hostCreateText,
  createComment: hostCreateComment,
  setText: hostSetText,
  setElementText: hostSetElementText,
  parentNode: hostParentNode,
  nextSibling: hostNextSibling,
  setScopeId: hostSetScopeId = NOOP,
  cloneNode: hostCloneNode,
  insertStaticContent: hostInsertStaticContent
} = options
// render
const render: RootRenderFunction = (vnode, container, isSVG) => {
  if (vnode == null) {
    if (container._vnode) {
      unmount(container._vnode, null, null, true)
    }
  } else {
    // 新舊節(jié)點(diǎn)的對(duì)比
    patch(container._vnode || null, vnode, container, null, null, null, isSVG)
  }
  flushPostFlushCbs()
  // 記錄舊節(jié)點(diǎn)
  container._vnode = vnode
}

patch

patch函數(shù)里主要對(duì)新舊節(jié)點(diǎn)也就是虛擬DOM的對(duì)比,常說(shuō)的vue里的diff算法,便是從patch開(kāi)始。結(jié)合render函數(shù)來(lái)看,我們知道,舊的虛擬DOM存儲(chǔ)在container._vnode上。那么diff的方式就在patch中了:

新舊節(jié)點(diǎn)相同,直接返回;

舊節(jié)點(diǎn)存在,且新舊節(jié)點(diǎn)類(lèi)型不同,則舊節(jié)點(diǎn)不可復(fù)用,將其卸載(unmount),錨點(diǎn)anchor移向下一個(gè)節(jié)點(diǎn);

新節(jié)點(diǎn)是否靜態(tài)節(jié)點(diǎn)標(biāo)記;

根據(jù)新節(jié)點(diǎn)的類(lèi)型,相應(yīng)地調(diào)用不同類(lèi)型的處理方法:

  • 文本:processText;
  • 注釋?zhuān)?code>processCommentNode;
  • 靜態(tài)節(jié)點(diǎn):mountStaticNodepatchStaticNode
  • 文檔片段:processFragment
  • 其它。

在 其它 這一項(xiàng)中,又根據(jù)形狀標(biāo)記 shapeFlag等,判斷是 元素節(jié)點(diǎn)、組件節(jié)點(diǎn),或是TeleportSuspense等,然后調(diào)用相應(yīng)的process去處理。最后處理template中的ref

// Note: functions inside this closure should use `const xxx = () => {}`
// style in order to prevent being inlined by minifiers.
const patch: PatchFn = (
  n1,
  n2,
  container,
  anchor = null,
  parentComponent = null,
  parentSuspense = null,
  isSVG = false,
  slotScopeIds = null,
  optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren
) => {
  // 新舊節(jié)點(diǎn)相同,直接返回
  if (n1 === n2) {
    return
  }
  // 舊節(jié)點(diǎn)存在,且新舊節(jié)點(diǎn)類(lèi)型不同,卸載舊節(jié)點(diǎn),錨點(diǎn)anchor后移
  // patching & not same type, unmount old tree
  if (n1 && !isSameVNodeType(n1, n2)) {
    anchor = getNextHostNode(n1)
    unmount(n1, parentComponent, parentSuspense, true)
    n1 = null
  }
  // 是否靜態(tài)節(jié)點(diǎn)優(yōu)化
  if (n2.patchFlag === PatchFlags.BAIL) {
    optimized = false
    n2.dynamicChildren = null
  }
  // 
  const { type, ref, shapeFlag } = n2
  switch (type) {
    case Text:
      processText(n1, n2, container, anchor)
      break
    case Comment:
      processCommentNode(n1, n2, container, anchor)
      break
    case Static:
      if (n1 == null) {
        mountStaticNode(n2, container, anchor, isSVG)
      } else if (__DEV__) {
        patchStaticNode(n1, n2, container, isSVG)
      }
      break
    case Fragment:
      processFragment(
        n1,
        n2,
        container,
        anchor,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds,
        optimized
      )
      break
    default:
      if (shapeFlag & ShapeFlags.ELEMENT) {
        processElement(
          n1,
          n2,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
      } else if (shapeFlag & ShapeFlags.COMPONENT) {
        processComponent(
          n1,
          n2,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
      } else if (shapeFlag & ShapeFlags.TELEPORT) {
        ;(type as typeof TeleportImpl).process(
          n1 as TeleportVNode,
          n2 as TeleportVNode,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized,
          internals
        )
      } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
        ;(type as typeof SuspenseImpl).process(
          n1,
          n2,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized,
          internals
        )
      } else if (__DEV__) {
        warn('Invalid VNode type:', type, `(${typeof type})`)
      }
  }
  // 處理 template 中的 ref 
  // set ref
  if (ref != null && parentComponent) {
    setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2)
  }
}

processText

文本節(jié)點(diǎn)的處理十分簡(jiǎn)單,沒(méi)有舊節(jié)點(diǎn)則新建并插入新節(jié)點(diǎn);有舊節(jié)點(diǎn),且節(jié)點(diǎn)內(nèi)容不一致,則設(shè)置為新節(jié)點(diǎn)的內(nèi)容。

const processText: ProcessTextOrCommentFn = (n1, n2, container, anchor) => {
  if (n1 == null) {
    hostInsert(
      (n2.el = hostCreateText(n2.children as string)),
      container,
      anchor
    )
  } else {
    const el = (n2.el = n1.el!)
    if (n2.children !== n1.children) {
      hostSetText(el, n2.children as string)
    }
  }
}

 processCommontNode

不支持動(dòng)態(tài)的注視節(jié)點(diǎn),因此只要舊節(jié)點(diǎn)存在,就使用舊節(jié)點(diǎn)的內(nèi)容。

const processCommentNode: ProcessTextOrCommentFn = (
    n1,
    n2,
    container,
    anchor
  ) => {
    if (n1 == null) {
      hostInsert(
        (n2.el = hostCreateComment((n2.children as string) || '')),
        container,
        anchor
      )
    } else {
      // there's no support for dynamic comments
      n2.el = n1.el
    }
  }

mountStaticNode 和 patchStaticNode

事實(shí)上靜態(tài)節(jié)點(diǎn)沒(méi)啥好比較的,畢竟是靜態(tài)的。當(dāng)沒(méi)有舊節(jié)點(diǎn)時(shí),則通過(guò)mountStaticNode創(chuàng)建并插入新節(jié)點(diǎn);即使有舊節(jié)點(diǎn),也僅在_DEV_條件下在hmr,才會(huì)使用patchStaticVnode做一下比較并通過(guò)removeStaticNode移除某些舊節(jié)點(diǎn)。

const mountStaticNode = (
  n2: VNode,
  container: RendererElement,
  anchor: RendererNode | null,
  isSVG: boolean
) => {
  // static nodes are only present when used with compiler-dom/runtime-dom
  // which guarantees presence of hostInsertStaticContent.
  ;[n2.el, n2.anchor] = hostInsertStaticContent!(
    n2.children as string,
    container,
    anchor,
    isSVG,
    n2.el,
    n2.anchor
  )
}
/**
 * Dev / HMR only
 */
const patchStaticNode = (
  n1: VNode,
  n2: VNode,
  container: RendererElement,
  isSVG: boolean
) => {
  // static nodes are only patched during dev for HMR
  if (n2.children !== n1.children) {
    const anchor = hostNextSibling(n1.anchor!)
    // 移除已有的靜態(tài)節(jié)點(diǎn),并插入新的節(jié)點(diǎn)
    // remove existing
    removeStaticNode(n1)
    // insert new
    ;[n2.el, n2.anchor] = hostInsertStaticContent!(
      n2.children as string,
      container,
      anchor,
      isSVG
    )
  } else {
    n2.el = n1.el
    n2.anchor = n1.anchor
  }
}
// removeStaticNode:從 n1.el 至 n1.anchor 的內(nèi)容被遍歷移除
const removeStaticNode = ({ el, anchor }: VNode) => {
  let next
  while (el && el !== anchor) {
    next = hostNextSibling(el)
    hostRemove(el)
    el = next
  }
  hostRemove(anchor!)
}

processFragment

vue3的單文件組件里,不再需要加一個(gè)根節(jié)點(diǎn),因?yàn)槭褂昧宋臋n片段fragment來(lái)承載子節(jié)點(diǎn),最后再一并添加到文檔中。

若舊的片段節(jié)點(diǎn)為空,則插入起始錨點(diǎn),掛載新的子節(jié)點(diǎn);

舊的片段不為空:

  • 存在優(yōu)化條件時(shí):使用patchBlockChildren優(yōu)化diff
  • 不存在優(yōu)化條件時(shí):使用patchChildren進(jìn)行全量diff。
const processFragment = (
  n1: VNode | null,
  n2: VNode,
  container: RendererElement,
  anchor: RendererNode | null,
  parentComponent: ComponentInternalInstance | null,
  parentSuspense: SuspenseBoundary | null,
  isSVG: boolean,
  slotScopeIds: string[] | null,
  optimized: boolean
) => {
  // 錨點(diǎn)
  const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateText(''))!
  const fragmentEndAnchor = (n2.anchor = n1 ? n1.anchor : hostCreateText(''))!
  let { patchFlag, dynamicChildren, slotScopeIds: fragmentSlotScopeIds } = n2
  // 開(kāi)發(fā)環(huán)境熱更新時(shí),強(qiáng)制全量diff
  if (
    __DEV__ &&
    // #5523 dev root fragment may inherit directives
    (isHmrUpdating || patchFlag & PatchFlags.DEV_ROOT_FRAGMENT)
  ) {
    // HMR updated / Dev root fragment (w/ comments), force full diff
    patchFlag = 0
    optimized = false
    dynamicChildren = null
  }
  // 檢查是否是插槽
  // check if this is a slot fragment with :slotted scope ids
  if (fragmentSlotScopeIds) {
    slotScopeIds = slotScopeIds
      ? slotScopeIds.concat(fragmentSlotScopeIds)
      : fragmentSlotScopeIds
  }
  // 當(dāng)舊的片段為空時(shí),掛載新的片段的子節(jié)點(diǎn)
  if (n1 == null) {
    hostInsert(fragmentStartAnchor, container, anchor)
    hostInsert(fragmentEndAnchor, container, anchor)
    // a fragment can only have array children
    // since they are either generated by the compiler, or implicitly created
    // from arrays.
    mountChildren(
      n2.children as VNodeArrayChildren,
      container,
      fragmentEndAnchor,
      parentComponent,
      parentSuspense,
      isSVG,
      slotScopeIds,
      optimized
    )
  } else {
    // 當(dāng)舊片段不為空時(shí),啟用優(yōu)化則使用patchBlockChildren
    if (
      patchFlag > 0 &&
      patchFlag & PatchFlags.STABLE_FRAGMENT &&
      dynamicChildren &&
      // #2715 the previous fragment could've been a BAILed one as a result
      // of renderSlot() with no valid children
      n1.dynamicChildren
    ) {
      // a stable fragment (template root or <template v-for>) doesn't need to
      // patch children order, but it may contain dynamicChildren.
      patchBlockChildren(
        n1.dynamicChildren,
        dynamicChildren,
        container,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds
      )
      // 開(kāi)發(fā)環(huán)境,熱更新 處理靜態(tài)子節(jié)點(diǎn)
      if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
        traverseStaticChildren(n1, n2)
      } else if (
        // #2080 if the stable fragment has a key, it's a <template v-for> that may
        //  get moved around. Make sure all root level vnodes inherit el.
        // #2134 or if it's a component root, it may also get moved around
        // as the component is being moved.
        n2.key != null ||
        (parentComponent && n2 === parentComponent.subTree)
      ) {
        traverseStaticChildren(n1, n2, true /* shallow */)
      }
    } else {
      // 不可優(yōu)化時(shí),使用patchChildren處理
      // keyed / unkeyed, or manual fragments.
      // for keyed & unkeyed, since they are compiler generated from v-for,
      // each child is guaranteed to be a block so the fragment will never
      // have dynamicChildren.
      patchChildren(
        n1,
        n2,
        container,
        fragmentEndAnchor,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds,
        optimized
      )
    }
  }
}

patchBlockChildren

在文檔片段中的diff中,當(dāng)符合優(yōu)化條件時(shí),則調(diào)用patchBlockChildren來(lái)進(jìn)行優(yōu)化的diff。這里主要以新節(jié)點(diǎn)的子節(jié)點(diǎn)長(zhǎng)度為準(zhǔn),遍歷新舊節(jié)點(diǎn)的子節(jié)點(diǎn),更新了每個(gè)子節(jié)點(diǎn)的container然后進(jìn)行patch。

// The fast path for blocks.
const patchBlockChildren: PatchBlockChildrenFn = (
  oldChildren,
  newChildren,
  fallbackContainer,
  parentComponent,
  parentSuspense,
  isSVG,
  slotScopeIds
) => {
  for (let i = 0; i < newChildren.length; i++) {
    const oldVNode = oldChildren[i]
    const newVNode = newChildren[i]
    // Determine the container (parent element) for the patch.
    const container =
      // oldVNode may be an errored async setup() component inside Suspense
      // which will not have a mounted element
      oldVNode.el &&
      // - In the case of a Fragment, we need to provide the actual parent
      // of the Fragment itself so it can move its children.
      (oldVNode.type === Fragment ||
        // - In the case of different nodes, there is going to be a replacement
        // which also requires the correct parent container
        !isSameVNodeType(oldVNode, newVNode) ||
        // - In the case of a component, it could contain anything.
        oldVNode.shapeFlag & (ShapeFlags.COMPONENT | ShapeFlags.TELEPORT))
        ? hostParentNode(oldVNode.el)!
        : // In other cases, the parent container is not actually used so we
          // just pass the block element here to avoid a DOM parentNode call.
          fallbackContainer
    patch(
      oldVNode,
      newVNode,
      container,
      null,
      parentComponent,
      parentSuspense,
      isSVG,
      slotScopeIds,
      true
    )
  }
}

patchChildren

在沒(méi)有優(yōu)化條件時(shí),使用patchChildren對(duì)子節(jié)點(diǎn)進(jìn)行全量的diff

const patchChildren: PatchChildrenFn = (
  n1,
  n2,
  container,
  anchor,
  parentComponent,
  parentSuspense,
  isSVG,
  slotScopeIds,
  optimized = false
) => {
  const c1 = n1 && n1.children
  const prevShapeFlag = n1 ? n1.shapeFlag : 0
  const c2 = n2.children
  const { patchFlag, shapeFlag } = n2
  // 走綠色通道:用patchFlag來(lái)保證children是數(shù)組
  // fast path
  if (patchFlag > 0) {
    if (patchFlag & PatchFlags.KEYED_FRAGMENT) {
      // 有key屬性的時(shí)候,根據(jù)key來(lái)進(jìn)行diff
      // this could be either fully-keyed or mixed (some keyed some not)
      // presence of patchFlag means children are guaranteed to be arrays
      patchKeyedChildren(
        c1 as VNode[],
        c2 as VNodeArrayChildren,
        container,
        anchor,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds,
        optimized
      )
      return
    } else if (patchFlag & PatchFlags.UNKEYED_FRAGMENT) {
      // 沒(méi)有key
      // unkeyed
      patchUnkeyedChildren(
        c1 as VNode[],
        c2 as VNodeArrayChildren,
        container,
        anchor,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds,
        optimized
      )
      return
    }
  }
  // 沒(méi)有patchFlag的保證,則children可能為文本、數(shù)組或空
  // 根據(jù)形狀標(biāo)識(shí)來(lái)判斷
  // children has 3 possibilities: text, array or no children.
  if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
    // 文本子節(jié)點(diǎn)的綠色通道
    // text children fast path
    if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
      unmountChildren(c1 as VNode[], parentComponent, parentSuspense)
    }
    if (c2 !== c1) {
      hostSetElementText(container, c2 as string)
    }
  } else {
    // 舊的子節(jié)點(diǎn)是數(shù)組
    if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
      // prev children was array
      if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
        // 新舊子節(jié)點(diǎn)都是數(shù)組,需要進(jìn)行全量diff
        // two arrays, cannot assume anything, do full diff
        patchKeyedChildren(
          c1 as VNode[],
          c2 as VNodeArrayChildren,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
      } else {
        // 新的子節(jié)點(diǎn)為空,則只需要卸載舊的子節(jié)點(diǎn)
        // no new children, just unmount old
        unmountChildren(c1 as VNode[], parentComponent, parentSuspense, true)
      }
    } else {
      // 舊的子節(jié)點(diǎn)為文本節(jié)點(diǎn)或者空,新的為數(shù)組或空
      // prev children was text OR null
      // new children is array OR null
      if (prevShapeFlag & ShapeFlags.TEXT_CHILDREN) {
        // 舊的為文本節(jié)點(diǎn),先將其文本置空
        hostSetElementText(container, '')
      }
      // 新的為數(shù)組,則通過(guò)mountChildren掛載子節(jié)點(diǎn)
      // mount new if array
      if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
        mountChildren(
          c2 as VNodeArrayChildren,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
      }
    }
  }
}

patchKeyedChildren

使用patchKeyedChildren來(lái)比較兩組有key,或者有key和沒(méi)有key混合的children,屬于diff的核心內(nèi)容了。

從前往后依次對(duì)比相同索引位置的節(jié)點(diǎn)類(lèi)型,當(dāng)遇到節(jié)點(diǎn)類(lèi)型不同則退出比較;

再?gòu)暮笸皩?duì)比相同倒序位置上的節(jié)點(diǎn)類(lèi)型,遇到不同類(lèi)型則退出比較;

如果舊節(jié)點(diǎn)組遍歷完,而新節(jié)點(diǎn)組還有內(nèi)容,則掛載新節(jié)點(diǎn)組里的剩余內(nèi)容;

如果新節(jié)點(diǎn)組遍歷完,而舊節(jié)點(diǎn)組還有內(nèi)容,則卸載舊節(jié)點(diǎn)組里的剩余內(nèi)容;

如果都沒(méi)有遍歷完:

  • 將新節(jié)點(diǎn)組的剩余內(nèi)容以key=>index的形式存入Map;
  • 遍歷剩余的舊子節(jié)點(diǎn),在Map中找到相同的key對(duì)應(yīng)的index;
  • 如果舊子節(jié)點(diǎn)沒(méi)有key,則找到新子節(jié)點(diǎn)組的剩余子節(jié)點(diǎn)中尚未被匹配到且類(lèi)型相同的節(jié)點(diǎn)對(duì)應(yīng)的index;
  • 求出最大遞增子序列;
  • 卸載不匹配的舊子節(jié)點(diǎn)、掛載未被匹配的新子節(jié)點(diǎn),移動(dòng)需要移動(dòng)的可復(fù)用子節(jié)點(diǎn)。
// can be all-keyed or mixed
const patchKeyedChildren = (
  c1: VNode[],
  c2: VNodeArrayChildren,
  container: RendererElement,
  parentAnchor: RendererNode | null,
  parentComponent: ComponentInternalInstance | null,
  parentSuspense: SuspenseBoundary | null,
  isSVG: boolean,
  slotScopeIds: string[] | null,
  optimized: boolean
) => {
  let i = 0
  const l2 = c2.length
  // 兩組各自的尾節(jié)點(diǎn)
  let e1 = c1.length - 1 // prev ending index
  let e2 = l2 - 1 // next ending index
  // (從前往后)
  // 以?xún)山M中最短的一組為基準(zhǔn)
  // 從頭結(jié)點(diǎn)開(kāi)始,依次比較同一位置的節(jié)點(diǎn)類(lèi)型,若頭節(jié)點(diǎn)類(lèi)型相同,則對(duì)兩個(gè)節(jié)點(diǎn)進(jìn)行patch進(jìn)行比較;
  // 若類(lèi)型不同則退出循環(huán)
  // 1. sync from start
  // (a b) c
  // (a b) d e
  while (i <= e1 && i <= e2) {
    const n1 = c1[i]
    const n2 = (c2[i] = optimized
      ? cloneIfMounted(c2[i] as VNode)
      : normalizeVNode(c2[i]))
    if (isSameVNodeType(n1, n2)) {
      patch(
        n1,
        n2,
        container,
        null,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds,
        optimized
      )
    } else {
      break
    }
    // 
    i++
  }
  // (從后往前)
  // 從尾節(jié)點(diǎn)開(kāi)始,尾節(jié)點(diǎn)類(lèi)型相同,則通過(guò)patch比較尾節(jié)點(diǎn);
  // 若類(lèi)型不同則退出循環(huán)
  // 2. sync from end
  // a (b c)
  // d e (b c)
  while (i <= e1 && i <= e2) {
    const n1 = c1[e1]
    const n2 = (c2[e2] = optimized
      ? cloneIfMounted(c2[e2] as VNode)
      : normalizeVNode(c2[e2]))
    if (isSameVNodeType(n1, n2)) {
      patch(
        n1,
        n2,
        container,
        null,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds,
        optimized
      )
    } else {
      break
    }
    e1--
    e2--
  }
  // 經(jīng)過(guò)前后兩輪比較之后,剩下的就是中間那部分類(lèi)型不同的子節(jié)點(diǎn)了
  // 若舊的子節(jié)點(diǎn)組已經(jīng)遍歷完,而新的子節(jié)點(diǎn)組還有剩余內(nèi)容
  // 通過(guò)patch處理剩下的新的子節(jié)點(diǎn)中的內(nèi)容,由于舊的子節(jié)點(diǎn)為空,
  // 因此相當(dāng)于在patch內(nèi)部掛載剩余的新的子節(jié)點(diǎn)
  // 3. common sequence + mount
  // (a b)
  // (a b) c
  // i = 2, e1 = 1, e2 = 2
  // (a b)
  // c (a b)
  // i = 0, e1 = -1, e2 = 0
  if (i > e1) {
    if (i <= e2) {
      const nextPos = e2 + 1
      const anchor = nextPos < l2 ? (c2[nextPos] as VNode).el : parentAnchor
      while (i <= e2) {
        patch(
          null,
          (c2[i] = optimized
            ? cloneIfMounted(c2[i] as VNode)
            : normalizeVNode(c2[i])),
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
        i++
      }
    }
  }
  // 舊的子節(jié)點(diǎn)還有剩余內(nèi)容而新的子節(jié)點(diǎn)組已經(jīng)遍歷完,則卸載舊子節(jié)點(diǎn)組剩余的那部分
  // 4. common sequence + unmount
  // (a b) c
  // (a b)
  // i = 2, e1 = 2, e2 = 1
  // a (b c)
  // (b c)
  // i = 0, e1 = 0, e2 = -1
  else if (i > e2) {
    while (i <= e1) {
      unmount(c1[i], parentComponent, parentSuspense, true)
      i++
    }
  }
  // 新舊子節(jié)點(diǎn)組都沒(méi)有遍歷完,如下注釋中[]里的部分
  // 5. unknown sequence
  // [i ... e1 + 1]: a b [c d e] f g
  // [i ... e2 + 1]: a b [e d c h] f g
  // i = 2, e1 = 4, e2 = 5
  else {
    // 拿到上次比較完的起點(diǎn)
    const s1 = i // prev starting index
    const s2 = i // next starting index
    // 5.1 build key:index map for newChildren
    const keyToNewIndexMap: Map<string | number | symbol, number> = new Map()
    // 用Map存儲(chǔ)新的子節(jié)點(diǎn)組的key和對(duì)應(yīng)的index, key=>index 并給出重復(fù)的key的警告
    for (i = s2; i <= e2; i++) {
      const nextChild = (c2[i] = optimized
        ? cloneIfMounted(c2[i] as VNode)
        : normalizeVNode(c2[i]))
      if (nextChild.key != null) {
        if (__DEV__ && keyToNewIndexMap.has(nextChild.key)) {
          warn(
            `Duplicate keys found during update:`,
            JSON.stringify(nextChild.key),
            `Make sure keys are unique.`
          )
        }
        keyToNewIndexMap.set(nextChild.key, i)
      }
    }
    // 5.2 loop through old children left to be patched and try to patch
    // matching nodes & remove nodes that are no longer present
    let j
    // 已比較的數(shù)量
    let patched = 0
    // 未比較的數(shù)量
    const toBePatched = e2 - s2 + 1
    let moved = false
    // used to track whether any node has moved
    let maxNewIndexSoFar = 0
    // works as Map<newIndex, oldIndex>
    // Note that oldIndex is offset by +1
    // and oldIndex = 0 is a special value indicating the new node has
    // no corresponding old node.
    // used for determining longest stable subsequence
    // 以新的子節(jié)點(diǎn)組中未完成比較的節(jié)點(diǎn)為基準(zhǔn)
    const newIndexToOldIndexMap = new Array(toBePatched)
    // 先用0來(lái)填充,標(biāo)記為沒(méi)有key的節(jié)點(diǎn)。 ps:直接fill(0)不就好了么
    for (i = 0; i < toBePatched; i++) newIndexToOldIndexMap[i] = 0
    // 處理舊的子節(jié)點(diǎn)組
    for (i = s1; i <= e1; i++) {
      const prevChild = c1[i]
      // 當(dāng)已經(jīng)比較完了(patched >= toBePatched),卸載舊的子節(jié)點(diǎn)
      if (patched >= toBePatched) {
        // all new children have been patched so this can only be a removal
        unmount(prevChild, parentComponent, parentSuspense, true)
        continue
      }
      let newIndex
      // 當(dāng)舊的子節(jié)點(diǎn)的key存在,取出key在新的子節(jié)點(diǎn)組中對(duì)應(yīng)的index
      if (prevChild.key != null) {
        newIndex = keyToNewIndexMap.get(prevChild.key)
      } else {
        // 若舊的子節(jié)點(diǎn)沒(méi)有key,找出沒(méi)有key且類(lèi)型相同的節(jié)點(diǎn)對(duì)應(yīng)在新子節(jié)點(diǎn)組中的index
        // key-less node, try to locate a key-less node of the same type
        for (j = s2; j <= e2; j++) {
          if (
            newIndexToOldIndexMap[j - s2] === 0 &&
            isSameVNodeType(prevChild, c2[j] as VNode)
          ) {
            newIndex = j
            break
          }
        }
      }
      // newIndex不存在,即根據(jù)key來(lái)找,發(fā)現(xiàn)舊的子節(jié)點(diǎn)不可復(fù)用,則卸載舊的子節(jié)點(diǎn)
      if (newIndex === undefined) {
        unmount(prevChild, parentComponent, parentSuspense, true)
      } else {
        // 找到了可復(fù)用的節(jié)點(diǎn),在newIndexToOldIndexMap中標(biāo)記 i+1,
        // 用于最大上升子序列算法
        newIndexToOldIndexMap[newIndex - s2] = i + 1
        // 刷新目前找到的最大的新子節(jié)點(diǎn)的index,做節(jié)點(diǎn)移動(dòng)標(biāo)記
        if (newIndex >= maxNewIndexSoFar) {
          maxNewIndexSoFar = newIndex
        } else {
          moved = true
        }
        // 再遞歸詳細(xì)比較兩個(gè)節(jié)點(diǎn)
        patch(
          prevChild,
          c2[newIndex] as VNode,
          container,
          null,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
        // 已對(duì)比的數(shù)量+1
        patched++
      }
    }
    // 當(dāng)需要移動(dòng)時(shí),采用最大遞增子序列算法,從而最大限度減少節(jié)點(diǎn)移動(dòng)次數(shù)
    // 5.3 move and mount
    // generate longest stable subsequence only when nodes have moved
    const increasingNewIndexSequence = moved
      ? getSequence(newIndexToOldIndexMap)
      : EMPTY_ARR
    j = increasingNewIndexSequence.length - 1
    // 倒序遍歷,好處是可以使用上一次對(duì)比的節(jié)點(diǎn)作為錨點(diǎn)
    // looping backwards so that we can use last patched node as anchor
    for (i = toBePatched - 1; i >= 0; i--) {
      const nextIndex = s2 + i
      const nextChild = c2[nextIndex] as VNode
      const anchor =
        nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchor
      if (newIndexToOldIndexMap[i] === 0) {
        // 等于0說(shuō)明未被舊的子節(jié)點(diǎn)匹配到,屬于全新的不可復(fù)用的子節(jié)點(diǎn),則通過(guò)patch進(jìn)行掛載
        // mount new
        patch(
          null,
          nextChild,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
      } else if (moved) {
        // 當(dāng)計(jì)算出來(lái)的最大上升子序列為空數(shù)組,
        // 或者當(dāng)前節(jié)點(diǎn)不處于最大上升子序列中
        // move if:
        // There is no stable subsequence (e.g. a reverse)
        // OR current node is not among the stable sequence
        if (j < 0 || i !== increasingNewIndexSequence[j]) {
          move(nextChild, container, anchor, MoveType.REORDER)
        } else {
          j--
        }
      }
    }
  }
}

patchUnkeyedChildren

沒(méi)有key的時(shí)候就很直接了,只依照最短的那組的長(zhǎng)度,來(lái)按位置進(jìn)行比較。而后該卸載就卸載,該掛載就掛載。

const patchUnkeyedChildren = (
  c1: VNode[],
  c2: VNodeArrayChildren,
  container: RendererElement,
  anchor: RendererNode | null,
  parentComponent: ComponentInternalInstance | null,
  parentSuspense: SuspenseBoundary | null,
  isSVG: boolean,
  slotScopeIds: string[] | null,
  optimized: boolean
) => {
  c1 = c1 || EMPTY_ARR
  c2 = c2 || EMPTY_ARR
  const oldLength = c1.length
  const newLength = c2.length
  const commonLength = Math.min(oldLength, newLength)
  let i
  for (i = 0; i < commonLength; i++) {
    const nextChild = (c2[i] = optimized
      ? cloneIfMounted(c2[i] as VNode)
      : normalizeVNode(c2[i]))
    patch(
      c1[i],
      nextChild,
      container,
      null,
      parentComponent,
      parentSuspense,
      isSVG,
      slotScopeIds,
      optimized
    )
  }
  if (oldLength > newLength) {
    // remove old
    unmountChildren(
      c1,
      parentComponent,
      parentSuspense,
      true,
      false,
      commonLength
    )
  } else {
    // mount new
    mountChildren(
      c2,
      container,
      anchor,
      parentComponent,
      parentSuspense,
      isSVG,
      slotScopeIds,
      optimized,
      commonLength
    )
  }
}

mountChildren

mountChildren用于掛載子節(jié)點(diǎn),主要是遍歷子節(jié)點(diǎn),處理每個(gè)子節(jié)點(diǎn),得到復(fù)制的或者標(biāo)準(zhǔn)化的單個(gè)子節(jié)點(diǎn),然后遞歸調(diào)用patch。

const mountChildren: MountChildrenFn = (
  children,
  container,
  anchor,
  parentComponent,
  parentSuspense,
  isSVG,
  slotScopeIds,
  optimized,
  start = 0
) => {
  for (let i = start; i < children.length; i++) {
    const child = (children[i] = optimized
      ? cloneIfMounted(children[i] as VNode)
      : normalizeVNode(children[i]))
    patch(
      null,
      child,
      container,
      anchor,
      parentComponent,
      parentSuspense,
      isSVG,
      slotScopeIds,
      optimized
    )
  }
}

unmountChildren

遍歷子節(jié)點(diǎn)組,調(diào)用unmount方法卸載子節(jié)點(diǎn)。

const unmountChildren: UnmountChildrenFn = (
  children,
  parentComponent,
  parentSuspense,
  doRemove = false,
  optimized = false,
  start = 0
) => {
  for (let i = start; i < children.length; i++) {
    unmount(children[i], parentComponent, parentSuspense, doRemove, optimized)
  }
}

move

在有key的子節(jié)點(diǎn)比較中,出現(xiàn)了需要移動(dòng)子節(jié)點(diǎn)的情況,而移動(dòng)就是通過(guò)move來(lái)完成的。按照不同的節(jié)點(diǎn)類(lèi)型,處理方式有所差異。

const move: MoveFn = (
  vnode,
  container,
  anchor,
  moveType,
  parentSuspense = null
) => {
  const { el, type, transition, children, shapeFlag } = vnode
  // 對(duì)于組件節(jié)點(diǎn),遞歸處理subTree
  if (shapeFlag & ShapeFlags.COMPONENT) {
    move(vnode.component!.subTree, container, anchor, moveType)
    return
  }
  // 處理異步組件<Suspense>
  if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
    vnode.suspense!.move(container, anchor, moveType)
    return
  }
  // 處理<Teleport>
  if (shapeFlag & ShapeFlags.TELEPORT) {
    ;(type as typeof TeleportImpl).move(vnode, container, anchor, internals)
    return
  }
  // 文檔片段,處理起始錨點(diǎn)和子節(jié)點(diǎn)
  if (type === Fragment) {
    hostInsert(el!, container, anchor)
    for (let i = 0; i < (children as VNode[]).length; i++) {
      move((children as VNode[])[i], container, anchor, moveType)
    }
    hostInsert(vnode.anchor!, container, anchor)
    return
  }
  // 靜態(tài)節(jié)點(diǎn)
  if (type === Static) {
    moveStaticNode(vnode, container, anchor)
    return
  }
  // 處理<Transition>的鉤子
  // single nodes
  const needTransition =
    moveType !== MoveType.REORDER &&
    shapeFlag & ShapeFlags.ELEMENT &&
    transition
  if (needTransition) {
    if (moveType === MoveType.ENTER) {
      transition!.beforeEnter(el!)
      hostInsert(el!, container, anchor)
      queuePostRenderEffect(() => transition!.enter(el!), parentSuspense)
    } else {
      const { leave, delayLeave, afterLeave } = transition!
      const remove = () => hostInsert(el!, container, anchor)
      const performLeave = () => {
        leave(el!, () => {
          remove()
          afterLeave && afterLeave()
        })
      }
      if (delayLeave) {
        delayLeave(el!, remove, performLeave)
      } else {
        performLeave()
      }
    }
  } else {
    hostInsert(el!, container, anchor)
  }
}

processElement

processElement內(nèi)容很簡(jiǎn)單,判斷一下是否要當(dāng)作svg處理;之后,如果舊節(jié)點(diǎn)為空,則直接通過(guò)mountElement掛載新的元素節(jié)點(diǎn),否則通過(guò)patchElement對(duì)元素節(jié)點(diǎn)進(jìn)行對(duì)比。

const processElement = (
    n1: VNode | null,
    n2: VNode,
    container: RendererElement,
    anchor: RendererNode | null,
    parentComponent: ComponentInternalInstance | null,
    parentSuspense: SuspenseBoundary | null,
    isSVG: boolean,
    slotScopeIds: string[] | null,
    optimized: boolean
  ) => {
    isSVG = isSVG || (n2.type as string) === 'svg'
    if (n1 == null) {
      mountElement(
        n2,
        container,
        anchor,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds,
        optimized
      )
    } else {
      patchElement(
        n1,
        n2,
        parentComponent,
        parentSuspense,
        isSVG,
        slotScopeIds,
        optimized
      )
    }
  }

mountElement

假如此時(shí)舊節(jié)點(diǎn)為空,那么就會(huì)調(diào)用mountElement,我們來(lái)看看它是怎么做的。

  • vndoe上的el屬性存在,開(kāi)發(fā)環(huán)境下則簡(jiǎn)單對(duì)el進(jìn)行復(fù)制;不存在則新建;
  • 先進(jìn)行子節(jié)點(diǎn)的掛載,因?yàn)槟承?code>props依賴(lài)于子節(jié)點(diǎn)的渲染;
  • 指令的created階段;
  • 處理props并設(shè)置scopeId;
  • 開(kāi)發(fā)環(huán)境下設(shè)置el.__vnodeel.vueParentComponent的取值,并設(shè)置為不可枚舉;
  • 指令的beforeMounted階段;
  • 動(dòng)畫(huà)組件TransitionbeforeEnter鉤子;
  • 執(zhí)行vnode上的鉤子、Transitionenter鉤子、指令的mounted鉤子等
const mountElement = (
    vnode: VNode,
    container: RendererElement,
    anchor: RendererNode | null,
    parentComponent: ComponentInternalInstance | null,
    parentSuspense: SuspenseBoundary | null,
    isSVG: boolean,
    slotScopeIds: string[] | null,
    optimized: boolean
  ) => {
    let el: RendererElement
    let vnodeHook: VNodeHook | undefined | null
    const { type, props, shapeFlag, transition, patchFlag, dirs } = vnode
    if (
      !__DEV__ &&
      vnode.el &&
      hostCloneNode !== undefined &&
      patchFlag === PatchFlags.HOISTED
    ) {
      // vnode的el元素存在,僅在生產(chǎn)環(huán)境下對(duì)可復(fù)用的靜態(tài)節(jié)點(diǎn)進(jìn)行復(fù)制
      // If a vnode has non-null el, it means it's being reused.
      // Only static vnodes can be reused, so its mounted DOM nodes should be
      // exactly the same, and we can simply do a clone here.
      // only do this in production since cloned trees cannot be HMR updated.
      el = vnode.el = hostCloneNode(vnode.el)
    } else {
      // vnode上的元素不存在則新建
      el = vnode.el = hostCreateElement(
        vnode.type as string,
        isSVG,
        props && props.is,
        props
      )
      // 注釋?zhuān)河捎谀承﹑rops依賴(lài)于子節(jié)點(diǎn)的渲染,先掛載子節(jié)點(diǎn)
      // mount children first, since some props may rely on child content
      // being already rendered, e.g. `<select value>`
      if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
        // 設(shè)置元素文本
        hostSetElementText(el, vnode.children as string)
      } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
        // 掛載子節(jié)點(diǎn)
        mountChildren(
          vnode.children as VNodeArrayChildren,
          el,
          null,
          parentComponent,
          parentSuspense,
          isSVG && type !== 'foreignObject',
          slotScopeIds,
          optimized
        )
      }
      // 指令的created階段
      if (dirs) {
        invokeDirectiveHook(vnode, null, parentComponent, 'created')
      }
      // 處理元素的props
      // props
      if (props) {
        for (const key in props) {
          if (key !== 'value' && !isReservedProp(key)) {
            hostPatchProp(
              el,
              key,
              null,
              props[key],
              isSVG,
              vnode.children as VNode[],
              parentComponent,
              parentSuspense,
              unmountChildren
            )
          }
        }
        /**
         * Special case for setting value on DOM elements:
         * - it can be order-sensitive (e.g. should be set *after* min/max, #2325, #4024)
         * - it needs to be forced (#1471)
         * #2353 proposes adding another renderer option to configure this, but
         * the properties affects are so finite it is worth special casing it
         * here to reduce the complexity. (Special casing it also should not
         * affect non-DOM renderers)
         */
        if ('value' in props) {
          hostPatchProp(el, 'value', null, props.value)
        }
        if ((vnodeHook = props.onVnodeBeforeMount)) {
          invokeVNodeHook(vnodeHook, parentComponent, vnode)
        }
      }
      // scopeId
      setScopeId(el, vnode, vnode.scopeId, slotScopeIds, parentComponent)
    }
    // __DEV__環(huán)境下處理 __vnode屬性和父組件為不可枚舉
    if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
      Object.defineProperty(el, '__vnode', {
        value: vnode,
        enumerable: false
      })
      Object.defineProperty(el, '__vueParentComponent', {
        value: parentComponent,
        enumerable: false
      })
    }
    // 執(zhí)行指令中的 beforeMount 階段
    if (dirs) {
      invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount')
    }
    // #1583 For inside suspense + suspense not resolved case, enter hook should call when suspense resolved
    // #1689 For inside suspense + suspense resolved case, just call it
    // 是否需要執(zhí)行動(dòng)畫(huà)組件鉤子
    const needCallTransitionHooks =
      (!parentSuspense || (parentSuspense && !parentSuspense.pendingBranch)) &&
      transition &&
      !transition.persisted
    if (needCallTransitionHooks) {
      transition!.beforeEnter(el)
    }
    hostInsert(el, container, anchor)
    if (
      (vnodeHook = props && props.onVnodeMounted) ||
      needCallTransitionHooks ||
      dirs
    ) {
      // 加入組件更新后的副作用執(zhí)行隊(duì)列,在合適的時(shí)機(jī)執(zhí)行入隊(duì)的函數(shù)
      // 這里是一些鉤子函數(shù)、trasition的鉤子、指令在mounted階段的鉤子
      queuePostRenderEffect(() => {
        vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)
        needCallTransitionHooks && transition!.enter(el)
        dirs && invokeDirectiveHook(vnode, null, parentComponent, 'mounted')
      }, parentSuspense)
    }
  }

patchElement

patchElemengt相當(dāng)重要,因?yàn)槠渌湍愣鄡?nèi)容的patch,最終經(jīng)過(guò)遞歸,依然會(huì)走到patchElement。當(dāng)新舊元素節(jié)點(diǎn)都存在時(shí),就會(huì)調(diào)用patchElement進(jìn)行對(duì)比??梢钥吹巾樞颍?/p>

beforeUpdated -> 子節(jié)點(diǎn) -> class/style -> 其它props/attrs -> updated

關(guān)閉recurse,處理beforeUpdated鉤子;

處理指定的beforeUpdated階段,再啟用recurse;

__DEV__環(huán)境下的熱更新時(shí),則會(huì)清理優(yōu)化標(biāo)記,從而強(qiáng)制對(duì)節(jié)點(diǎn)進(jìn)行全量的比較(full diff);

處理動(dòng)態(tài)子節(jié)點(diǎn):

  • 當(dāng)新節(jié)點(diǎn)中有動(dòng)態(tài)子節(jié)點(diǎn),則通過(guò)patchBlockChildren來(lái)和舊節(jié)點(diǎn)的動(dòng)態(tài)子節(jié)點(diǎn)進(jìn)行對(duì)比;
  • 否則,如果沒(méi)有優(yōu)化(!optimized),則使用patchChildren對(duì)子節(jié)點(diǎn)進(jìn)行全量diff;

判斷patchFlag > 0,大于0時(shí)則元素的render代碼由compiler生成,有優(yōu)化buff

  • 如果props中有動(dòng)態(tài)的key,則優(yōu)化無(wú)效,進(jìn)行全量diff;
  • 處理動(dòng)態(tài)類(lèi)名和動(dòng)態(tài)style,優(yōu)化diff
  • 處理其它的prop/attr,如果其中有動(dòng)態(tài)的key,則優(yōu)化無(wú)效;
  • 處理文本:當(dāng)元素只有文本子節(jié)點(diǎn)時(shí),則將文本子節(jié)點(diǎn)設(shè)置為新的元素節(jié)點(diǎn)的內(nèi)容;

patchFlag <= 0,且沒(méi)有設(shè)置優(yōu)化時(shí),對(duì)props進(jìn)行全量diff

updated階段。

const patchElement = (
  n1: VNode,
  n2: VNode,
  parentComponent: ComponentInternalInstance | null,
  parentSuspense: SuspenseBoundary | null,
  isSVG: boolean,
  slotScopeIds: string[] | null,
  optimized: boolean
) => {
  const el = (n2.el = n1.el!)
  let { patchFlag, dynamicChildren, dirs } = n2
  // #1426 take the old vnode's patch flag into account since user may clone a
  // compiler-generated vnode, which de-opts to FULL_PROPS
  patchFlag |= n1.patchFlag & PatchFlags.FULL_PROPS
  const oldProps = n1.props || EMPTY_OBJ
  const newProps = n2.props || EMPTY_OBJ
  let vnodeHook: VNodeHook | undefined | null
  // 關(guān)閉recurse,在 beforeUpdated 階段不允許自己調(diào)用
  // disable recurse in beforeUpdate hooks
  parentComponent && toggleRecurse(parentComponent, false)
  // beforeUpdated鉤子
  if ((vnodeHook = newProps.onVnodeBeforeUpdate)) {
    invokeVNodeHook(vnodeHook, parentComponent, n2, n1)
  }
  // 指令的 beforeUpdated 鉤子
  if (dirs) {
    invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')
  }
  // 允許自己調(diào)用
  parentComponent && toggleRecurse(parentComponent, true)
  // 開(kāi)發(fā)環(huán)境呢下,關(guān)閉優(yōu)化,全量diff
  if (__DEV__ && isHmrUpdating) {
    // HMR updated, force full diff
    patchFlag = 0
    optimized = false
    dynamicChildren = null
  }
  const areChildrenSVG = isSVG && n2.type !== 'foreignObject'
  // 新節(jié)點(diǎn)的動(dòng)態(tài)子節(jié)點(diǎn)不為空,則比較新舊節(jié)點(diǎn)的動(dòng)態(tài)子節(jié)點(diǎn)
  if (dynamicChildren) {
    patchBlockChildren(
      n1.dynamicChildren!,
      dynamicChildren,
      el,
      parentComponent,
      parentSuspense,
      areChildrenSVG,
      slotScopeIds
    )
    // 開(kāi)發(fā)環(huán)境  遞歸遍歷靜態(tài)子節(jié)點(diǎn)
    if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
      traverseStaticChildren(n1, n2)
    }
    // 沒(méi)有優(yōu)化,全量 diff
  } else if (!optimized) {
    // full diff
    patchChildren(
      n1,
      n2,
      el,
      null,
      parentComponent,
      parentSuspense,
      areChildrenSVG,
      slotScopeIds,
      false
    )
  }
  // 注釋?zhuān)簆atchFlag 標(biāo)識(shí)的存在意味著元素的 render 代碼是由 compiler 生成的,
  // 且可以在 patch 時(shí)走快道,此時(shí)能保證新舊節(jié)點(diǎn)形狀相同,即它們?cè)谠茨0逯姓锰幱谙嗤奈恢?
  // 此時(shí)的對(duì)比是有著各種優(yōu)化的
  if (patchFlag > 0) {
    // the presence of a patchFlag means this element's render code was
    // generated by the compiler and can take the fast path.
    // in this path old node and new node are guaranteed to have the same shape
    // (i.e. at the exact same position in the source template)
    if (patchFlag & PatchFlags.FULL_PROPS) {
      // 當(dāng)props中含有動(dòng)態(tài)的key,需要進(jìn)行全量 diff
      // element props contain dynamic keys, full diff needed
      patchProps(
        el,
        n2,
        oldProps,
        newProps,
        parentComponent,
        parentSuspense,
        isSVG
      )
    } else {
      // 處理動(dòng)態(tài)類(lèi)名綁定
      // class
      // this flag is matched when the element has dynamic class bindings.
      if (patchFlag & PatchFlags.CLASS) {
        if (oldProps.class !== newProps.class) {
          hostPatchProp(el, 'class', null, newProps.class, isSVG)
        }
      }
      // 處理動(dòng)態(tài)的 style 綁定
      // style
      // this flag is matched when the element has dynamic style bindings
      if (patchFlag & PatchFlags.STYLE) {
        hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG)
      }
      // 處理動(dòng)態(tài)的 prop/attr 綁定,有迭代緩存,優(yōu)化比較速度
      // 如果 `prop/attr`的 key 是動(dòng)態(tài)的,那么這種優(yōu)化則會(huì)失效
      // props
      // This flag is matched when the element has dynamic prop/attr bindings
      // other than class and style. The keys of dynamic prop/attrs are saved for
      // faster iteration.
      // Note dynamic keys like :[foo]="bar" will cause this optimization to
      // bail out and go through a full diff because we need to unset the old key
      if (patchFlag & PatchFlags.PROPS) {
        // if the flag is present then dynamicProps must be non-null
        const propsToUpdate = n2.dynamicProps!
        for (let i = 0; i < propsToUpdate.length; i++) {
          const key = propsToUpdate[i]
          const prev = oldProps[key]
          const next = newProps[key]
          // value屬性會(huì)被強(qiáng)行對(duì)比
          // #1471 force patch value
          if (next !== prev || key === 'value') {
            hostPatchProp(
              el,
              key,
              prev,
              next,
              isSVG,
              n1.children as VNode[],
              parentComponent,
              parentSuspense,
              unmountChildren
            )
          }
        }
      }
    }
    // 處理文本:僅在元素只有文本子節(jié)點(diǎn)時(shí)觸發(fā)
    // text
    // This flag is matched when the element has only dynamic text children.
    if (patchFlag & PatchFlags.TEXT) {
      if (n1.children !== n2.children) {
        hostSetElementText(el, n2.children as string)
      }
    }
  } else if (!optimized && dynamicChildren == null) {
    // 沒(méi)有優(yōu)化,全量 diff
    // unoptimized, full diff
    patchProps(
      el,
      n2,
      oldProps,
      newProps,
      parentComponent,
      parentSuspense,
      isSVG
    )
  }
  // updated 鉤子 入隊(duì)
  if ((vnodeHook = newProps.onVnodeUpdated) || dirs) {
    queuePostRenderEffect(() => {
      vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1)
      dirs && invokeDirectiveHook(n2, n1, parentComponent, 'updated')
    }, parentSuspense)
  }
}

patchElement中,注意到當(dāng)新節(jié)點(diǎn)具有動(dòng)態(tài)子節(jié)點(diǎn)時(shí),調(diào)用了patchBlockChildren來(lái)進(jìn)行子節(jié)點(diǎn)的比較,而在沒(méi)有動(dòng)態(tài)子節(jié)點(diǎn)且不符合優(yōu)化條件時(shí),則使用patchChildren來(lái)比較。這與processFragment類(lèi)似。

而當(dāng)patchFlag <= 0且沒(méi)有設(shè)置優(yōu)化時(shí),對(duì)props進(jìn)行全量diff。分別遍歷新的props和舊的props,最后刷新value的值。

const patchProps = (
  el: RendererElement,
  vnode: VNode,
  oldProps: Data,
  newProps: Data,
  parentComponent: ComponentInternalInstance | null,
  parentSuspense: SuspenseBoundary | null,
  isSVG: boolean
) => {
  if (oldProps !== newProps) {
    // 遍歷新的props
    for (const key in newProps) {
      // empty string is not valid prop
      if (isReservedProp(key)) continue
      const next = newProps[key]
      const prev = oldProps[key]
      // 先不比較 value
      // defer patching value
      if (next !== prev && key !== 'value') {
        hostPatchProp(
          el,
          key,
          prev,
          next,
          isSVG,
          vnode.children as VNode[],
          parentComponent,
          parentSuspense,
          unmountChildren
        )
      }
    }
    // 遍歷舊的props
    if (oldProps !== EMPTY_OBJ) {
      for (const key in oldProps) {
        if (!isReservedProp(key) && !(key in newProps)) {
          hostPatchProp(
            el,
            key,
            oldProps[key],
            null,
            isSVG,
            vnode.children as VNode[],
            parentComponent,
            parentSuspense,
            unmountChildren
          )
        }
      }
    }
    // 最后處理 value
    if ('value' in newProps) {
      hostPatchProp(el, 'value', oldProps.value, newProps.value)
    }
  }
}

processComponent

當(dāng)被patch的節(jié)點(diǎn)類(lèi)型是組件時(shí),通過(guò)processComponent來(lái)處理。

當(dāng)舊組件節(jié)點(diǎn)存在時(shí),則調(diào)用updateComponent進(jìn)行更新;

否則:

  • 當(dāng)新組件節(jié)點(diǎn)為KeepAlive時(shí),調(diào)用其上下文對(duì)象上的activate方法;
  • 否則,使用mountComponent掛載新的組件節(jié)點(diǎn);
const processComponent = (
  n1: VNode | null,
  n2: VNode,
  container: RendererElement,
  anchor: RendererNode | null,
  parentComponent: ComponentInternalInstance | null,
  parentSuspense: SuspenseBoundary | null,
  isSVG: boolean,
  slotScopeIds: string[] | null,
  optimized: boolean
) => {
  n2.slotScopeIds = slotScopeIds
  if (n1 == null) {
    if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
      ;(parentComponent!.ctx as KeepAliveContext).activate(
        n2,
        container,
        anchor,
        isSVG,
        optimized
      )
    } else {
      mountComponent(
        n2,
        container,
        anchor,
        parentComponent,
        parentSuspense,
        isSVG,
        optimized
      )
    }
  } else {
    updateComponent(n1, n2, optimized)
  }
}

mountComponent

mountComponent在舊的組件節(jié)點(diǎn)不存在時(shí)被調(diào)用。所有的mountXXX最常見(jiàn)的調(diào)用時(shí)機(jī)都是首次渲染時(shí),舊節(jié)點(diǎn)都是空的。

const mountComponent: MountComponentFn = (
  initialVNode,
  container,
  anchor,
  parentComponent,
  parentSuspense,
  isSVG,
  optimized
) => {
  // 2.x compat may pre-create the component instance before actually
  // mounting
  const compatMountInstance =
    __COMPAT__ && initialVNode.isCompatRoot && initialVNode.component
  const instance: ComponentInternalInstance =
    compatMountInstance ||
    (initialVNode.component = createComponentInstance(
      initialVNode,
      parentComponent,
      parentSuspense
    ))
  // 注冊(cè)熱更新
  if (__DEV__ && instance.type.__hmrId) {
    registerHMR(instance)
  }
  // 掛載性能檢測(cè)
  if (__DEV__) {
    pushWarningContext(initialVNode)
    startMeasure(instance, `mount`)
  }
  // 注入renderer的內(nèi)部?jī)?nèi)容
  // inject renderer internals for keepAlive
  if (isKeepAlive(initialVNode)) {
    ;(instance.ctx as KeepAliveContext).renderer = internals
  }
  /** 這里備注一下 internals 的內(nèi)容
   * const internals: RendererInternals = {
   *   p: patch,
   *   um: unmount,
   *   m: move,
   *   r: remove,
   *   mt: mountComponent,
   *   mc: mountChildren,
   *   pc: patchChildren,
   *   pbc: patchBlockChildren,
   *   n: getNextHostNode,
   *   o: options
   * }
   */
  // 處理props和插槽
  // resolve props and slots for setup context
  if (!(__COMPAT__ && compatMountInstance)) {
    // 檢測(cè)初始化性能
    if (__DEV__) {
      startMeasure(instance, `init`)
    }
    // 處理setup:這個(gè)函數(shù)里使用其它方法,初始化了props和插槽,且調(diào)用了setup
    setupComponent(instance)
    if (__DEV__) {
      endMeasure(instance, `init`)
    }
  }
  // 處理異步的setup
  // setup() is async. This component relies on async logic to be resolved
  // before proceeding
  if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
    parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect)
    // Give it a placeholder if this is not hydration
    // TODO handle self-defined fallback
    if (!initialVNode.el) {
      const placeholder = (instance.subTree = createVNode(Comment))
      processCommentNode(null, placeholder, container!, anchor)
    }
    return
  }
  // 接下來(lái)根據(jù)setup返回內(nèi)容進(jìn)行渲染
  // todo 閱讀該函數(shù)的內(nèi)容
  setupRenderEffect(
    instance,
    initialVNode,
    container,
    anchor,
    parentSuspense,
    isSVG,
    optimized
  )
  // mount性能檢測(cè)結(jié)束點(diǎn)
  if (__DEV__) {
    popWarningContext()
    endMeasure(instance, `mount`)
  }
}

updateComponent

當(dāng)舊的組件節(jié)點(diǎn)存在時(shí),對(duì)組件節(jié)點(diǎn)的處理會(huì)進(jìn)入到更新階段,也就是updateComponent。以舊組件為基準(zhǔn)拿到實(shí)例instance,通過(guò)shouldUpdateComponent判斷是否要更新組件。如果不需要更新,則只復(fù)制一下屬性;否則,當(dāng)實(shí)例是異步組件時(shí),則只更新props和插槽;當(dāng)實(shí)例是同步組件時(shí),則設(shè)置next為新的組件節(jié)點(diǎn),并調(diào)用組件的update方法進(jìn)行更新。

const updateComponent = (n1: VNode, n2: VNode, optimized: boolean) => {
  const instance = (n2.component = n1.component)!
  if (shouldUpdateComponent(n1, n2, optimized)) {
    if (
      __FEATURE_SUSPENSE__ &&
      instance.asyncDep &&
      !instance.asyncResolved
    ) {
      // async & still pending - just update props and slots
      // since the component's reactive effect for render isn't set-up yet
      if (__DEV__) {
        pushWarningContext(n2)
      }
      // 更新組件的預(yù)渲染:即處理props和插槽
      updateComponentPreRender(instance, n2, optimized)
      if (__DEV__) {
        popWarningContext()
      }
      return
    } else {
      // normal update
      instance.next = n2
      // in case the child component is also queued, remove it to avoid
      // double updating the same child component in the same flush.
      invalidateJob(instance.update)
      // instance.update is the reactive effect.
      instance.update()
    }
  } else {
    // no update needed. just copy over properties
    n2.el = n1.el
    instance.vnode = n2
  }
}

updateComponentPreRender

組件的預(yù)渲染,即在這里處理props和插槽。

const updateComponentPreRender = (
  instance: ComponentInternalInstance,
  nextVNode: VNode,
  optimized: boolean
) => {
  nextVNode.component = instance
  const prevProps = instance.vnode.props
  instance.vnode = nextVNode
  instance.next = null
  updateProps(instance, nextVNode.props, prevProps, optimized)
  updateSlots(instance, nextVNode.children, optimized)
  pauseTracking()
  // props update may have triggered pre-flush watchers.
  // flush them before the render update.
  flushPreFlushCbs(undefined, instance.update)
  resetTracking()
}

setupRenderEffect

相當(dāng)重要的一個(gè)函數(shù)。用componentUpdateFn來(lái)創(chuàng)建一個(gè)effect。最后執(zhí)行的update函數(shù)以及實(shí)例的update方法,都是執(zhí)行effect.run。而effect.run內(nèi)部會(huì)進(jìn)行與依賴(lài)收集相關(guān)的操作,還會(huì)調(diào)用新建effect時(shí)傳入的函數(shù)componentUpdateFn。這里可以看到**componentUpdateFn分為掛載和更新兩部分**。

const setupRenderEffect: SetupRenderEffectFn = (
  instance,
  initialVNode,
  container,
  anchor,
  parentSuspense,
  isSVG,
  optimized
) => {
  const componentUpdateFn = () => {
    if (!instance.isMounted) {
      let vnodeHook: VNodeHook | null | undefined
      const { el, props } = initialVNode
      const { bm, m, parent } = instance
      const isAsyncWrapperVNode = isAsyncWrapper(initialVNode)
      // 在beforeMounted期間 不允許effect自己調(diào)用
      toggleRecurse(instance, false)
      // beforeMount hook
      if (bm) {
        invokeArrayFns(bm)
      }
      // onVnodeBeforeMount
      if (
        !isAsyncWrapperVNode &&
        (vnodeHook = props && props.onVnodeBeforeMount)
      ) {
        invokeVNodeHook(vnodeHook, parent, initialVNode)
      }
      if (
        __COMPAT__ &&
        isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
      ) {
        instance.emit('hook:beforeMount')
      }
      toggleRecurse(instance, true)
      if (el && hydrateNode) {
        // vnode has adopted host node - perform hydration instead of mount.
        const hydrateSubTree = () => {
          if (__DEV__) {
            startMeasure(instance, `render`)
          }
          instance.subTree = renderComponentRoot(instance)
          if (__DEV__) {
            endMeasure(instance, `render`)
          }
          if (__DEV__) {
            startMeasure(instance, `hydrate`)
          }
          hydrateNode!(
            el as Node,
            instance.subTree,
            instance,
            parentSuspense,
            null
          )
          if (__DEV__) {
            endMeasure(instance, `hydrate`)
          }
        }
        if (isAsyncWrapperVNode) {
          ;(initialVNode.type as ComponentOptions).__asyncLoader!().then(
            // note: we are moving the render call into an async callback,
            // which means it won't track dependencies - but it's ok because
            // a server-rendered async wrapper is already in resolved state
            // and it will never need to change.
            () => !instance.isUnmounted && hydrateSubTree()
          )
        } else {
          hydrateSubTree()
        }
      } else {
        if (__DEV__) {
          startMeasure(instance, `render`)
        }
        const subTree = (instance.subTree = renderComponentRoot(instance))
        if (__DEV__) {
          endMeasure(instance, `render`)
        }
        if (__DEV__) {
          startMeasure(instance, `patch`)
        }
        patch(
          null,
          subTree,
          container,
          anchor,
          instance,
          parentSuspense,
          isSVG
        )
        if (__DEV__) {
          endMeasure(instance, `patch`)
        }
        initialVNode.el = subTree.el
      }
      // mounted鉤子入隊(duì)
      // mounted hook
      if (m) {
        queuePostRenderEffect(m, parentSuspense)
      }
      // onVnodeMounted
      if (
        !isAsyncWrapperVNode &&
        (vnodeHook = props && props.onVnodeMounted)
      ) {
        const scopedInitialVNode = initialVNode
        queuePostRenderEffect(
          () => invokeVNodeHook(vnodeHook!, parent, scopedInitialVNode),
          parentSuspense
        )
      }
      if (
        __COMPAT__ &&
        isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
      ) {
        queuePostRenderEffect(
          () => instance.emit('hook:mounted'),
          parentSuspense
        )
      }
      // <KeepAlive>組件的activated鉤子,可能包含從子組件注入的鉤子
      // activated hook for keep-alive roots.
      // #1742 activated hook must be accessed after first render
      // since the hook may be injected by a child keep-alive
      if (
        initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE ||
        (parent &&
          isAsyncWrapper(parent.vnode) &&
          parent.vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE)
      ) {
        instance.a && queuePostRenderEffect(instance.a, parentSuspense)
        // 兼容
        if (
          __COMPAT__ &&
          isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
        ) {
          queuePostRenderEffect(
            () => instance.emit('hook:activated'),
            parentSuspense
          )
        }
      }
      // 變更組件掛載狀態(tài)
      instance.isMounted = true
      if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
        devtoolsComponentAdded(instance)
      }
      // #2458: deference mount-only object parameters to prevent memleaks
      initialVNode = container = anchor = null as any
    } else {
      // updateComponent
      // This is triggered by mutation of component's own state (next: null)
      // OR parent calling processComponent (next: VNode)
      let { next, bu, u, parent, vnode } = instance
      let originNext = next
      let vnodeHook: VNodeHook | null | undefined
      if (__DEV__) {
        pushWarningContext(next || instance.vnode)
      }
      // beforeUpdated 期間也不允許effect自調(diào)用
      // Disallow component effect recursion during pre-lifecycle hooks.
      toggleRecurse(instance, false)
      if (next) {
        next.el = vnode.el
        updateComponentPreRender(instance, next, optimized)
      } else {
        next = vnode
      }
      // beforeUpdate hook
      if (bu) {
        invokeArrayFns(bu)
      }
      // onVnodeBeforeUpdate
      if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {
        invokeVNodeHook(vnodeHook, parent, next, vnode)
      }
      // 考慮兼容
      if (
        __COMPAT__ &&
        isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
      ) {
        instance.emit('hook:beforeUpdate')
      }
      toggleRecurse(instance, true)
      // render
      if (__DEV__) {
        startMeasure(instance, `render`)
      }
      const nextTree = renderComponentRoot(instance)
      if (__DEV__) {
        endMeasure(instance, `render`)
      }
      const prevTree = instance.subTree
      instance.subTree = nextTree
      if (__DEV__) {
        startMeasure(instance, `patch`)
      }
      // 更新則比較新舊subTree
      patch(
        prevTree,
        nextTree,
        // parent may have changed if it's in a teleport
        hostParentNode(prevTree.el!)!,
        // anchor may have changed if it's in a fragment
        getNextHostNode(prevTree),
        instance,
        parentSuspense,
        isSVG
      )
      if (__DEV__) {
        endMeasure(instance, `patch`)
      }
      next.el = nextTree.el
      if (originNext === null) {
        // self-triggered update. In case of HOC, update parent component
        // vnode el. HOC is indicated by parent instance's subTree pointing
        // to child component's vnode
        updateHOCHostEl(instance, nextTree.el)
      }
      // 處理updated鉤子
      // updated hook
      if (u) {
        queuePostRenderEffect(u, parentSuspense)
      }
      // onVnodeUpdated
      if ((vnodeHook = next.props && next.props.onVnodeUpdated)) {
        queuePostRenderEffect(
          () => invokeVNodeHook(vnodeHook!, parent, next!, vnode),
          parentSuspense
        )
      }
      if (
        __COMPAT__ &&
        isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
      ) {
        queuePostRenderEffect(
          () => instance.emit('hook:updated'),
          parentSuspense
        )
      }
      if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
        devtoolsComponentUpdated(instance)
      }
      if (__DEV__) {
        popWarningContext()
      }
    }
  }
  // 使用componentUpdateFn創(chuàng)建effect
  // create reactive effect for rendering
  const effect = (instance.effect = new ReactiveEffect(
    componentUpdateFn,
    () => queueJob(update),
    instance.scope // track it in component's effect scope
  ))
  const update: SchedulerJob = (instance.update = () => effect.run())
  update.id = instance.uid
  // allowRecurse
  // #1801, #2043 component render effects should allow recursive updates
  toggleRecurse(instance, true)
  // 用于開(kāi)發(fā)調(diào)試
  if (__DEV__) {
    effect.onTrack = instance.rtc
      ? e => invokeArrayFns(instance.rtc!, e)
      : void 0
    effect.onTrigger = instance.rtg
      ? e => invokeArrayFns(instance.rtg!, e)
      : void 0
    update.ownerInstance = instance
  }
  // 調(diào)用一次更新
  update()
}

unmount

舊節(jié)點(diǎn)的卸載通過(guò)unmount來(lái)處理,其中根據(jù)節(jié)點(diǎn)類(lèi)型不同,又有著不同的函數(shù)來(lái)實(shí)施卸載。

經(jīng)過(guò)置空ref、判斷與處理KeepAlive、beforeUnmounted的鉤子函數(shù)和指令、判斷組件的類(lèi)型并相應(yīng)卸載、處理unmounted鉤子和指令等過(guò)程。

const unmount: UnmountFn = (
  vnode,
  parentComponent,
  parentSuspense,
  doRemove = false,
  optimized = false
) => {
  const {
    type,
    props,
    ref,
    children,
    dynamicChildren,
    shapeFlag,
    patchFlag,
    dirs
  } = vnode
  // 置空ref
  // unset ref
  if (ref != null) {
    setRef(ref, null, parentSuspense, vnode, true)
  }
  // 組件被緩存,則調(diào)用<KeepAlive>的失活方法 deactivate
  if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
    ;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)
    return
  }
  // 是否調(diào)用指令和鉤子
  const shouldInvokeDirs = shapeFlag & ShapeFlags.ELEMENT && dirs
  const shouldInvokeVnodeHook = !isAsyncWrapper(vnode)
  // beforeUnmounted 鉤子
  let vnodeHook: VNodeHook | undefined | null
  if (
    shouldInvokeVnodeHook &&
    (vnodeHook = props && props.onVnodeBeforeUnmount)
  ) {
    invokeVNodeHook(vnodeHook, parentComponent, vnode)
  }
  if (shapeFlag & ShapeFlags.COMPONENT) {
    // 卸載組件
    unmountComponent(vnode.component!, parentSuspense, doRemove)
  } else {
    // 卸載異步組件
    if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
      vnode.suspense!.unmount(parentSuspense, doRemove)
      return
    }
    // 處理指令的 beforeUnmounted 階段
    if (shouldInvokeDirs) {
      invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount')
    }
    // 卸載 Teleport
    if (shapeFlag & ShapeFlags.TELEPORT) {
      ;(vnode.type as typeof TeleportImpl).remove(
        vnode,
        parentComponent,
        parentSuspense,
        optimized,
        internals,
        doRemove
      )
    } else if (
      dynamicChildren &&
      // #1153: fast path should not be taken for non-stable (v-for) fragments
      (type !== Fragment ||
        (patchFlag > 0 && patchFlag & PatchFlags.STABLE_FRAGMENT))
    ) {
      // 對(duì)于優(yōu)化過(guò)的塊狀節(jié)點(diǎn),僅需移除動(dòng)態(tài)子節(jié)點(diǎn)
      // fast path for block nodes: only need to unmount dynamic children.
      unmountChildren(
        dynamicChildren,
        parentComponent,
        parentSuspense,
        false,
        true
      )
    } else if (
      // 文檔片段  移除其子節(jié)點(diǎn)
      (type === Fragment &&
        patchFlag &
          (PatchFlags.KEYED_FRAGMENT | PatchFlags.UNKEYED_FRAGMENT)) ||
      (!optimized && shapeFlag & ShapeFlags.ARRAY_CHILDREN)
    ) {
      unmountChildren(children as VNode[], parentComponent, parentSuspense)
    }
    // 處理節(jié)點(diǎn)自身
    if (doRemove) {
      remove(vnode)
    }
  }
  // 處理 unmounted 鉤子以及指令中的 unmounted 階段
  if (
    (shouldInvokeVnodeHook &&
      (vnodeHook = props && props.onVnodeUnmounted)) ||
    shouldInvokeDirs
  ) {
    queuePostRenderEffect(() => {
      vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)
      shouldInvokeDirs &&
        invokeDirectiveHook(vnode, null, parentComponent, 'unmounted')
    }, parentSuspense)
  }
}

remove

使用remove來(lái)移除一個(gè)節(jié)點(diǎn)。根據(jù)節(jié)點(diǎn)類(lèi)型與環(huán)境,執(zhí)行的邏輯也稍有差別。

const remove: RemoveFn = vnode => {
  const { type, el, anchor, transition } = vnode
  if (type === Fragment) {
    if (
      __DEV__ &&
      vnode.patchFlag > 0 &&
      vnode.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT &&
      transition &&
      !transition.persisted
    ) {
      // __DEV__環(huán)境
      // 遍歷移除子節(jié)點(diǎn)
      ;(vnode.children as VNode[]).forEach(child => {
        if (child.type === Comment) {
          hostRemove(child.el!)
        } else {
          remove(child)
        }
      })
    } else {
      // 移除片段
      removeFragment(el!, anchor!)
    }
    return
  }
  // 移除靜態(tài)節(jié)點(diǎn)
  if (type === Static) {
    removeStaticNode(vnode)
    return
  }
  /** 遍歷移除靜態(tài)節(jié)點(diǎn)
   *  const removeStaticNode = ({ el, anchor }: VNode) => {
   *    let next
   *    while (el && el !== anchor) {
   *      next = hostNextSibling(el)
   *      hostRemove(el)
   *      el = next
   *    }
   *    hostRemove(anchor!)
   *  }
   */
  const performRemove = () => {
    // 移除el
    hostRemove(el!)
    if (transition && !transition.persisted && transition.afterLeave) {
      // 動(dòng)畫(huà)的 afterLeave 鉤子
      transition.afterLeave()
    }
  }
  if (
    vnode.shapeFlag & ShapeFlags.ELEMENT &&
    transition &&
    !transition.persisted
  ) {
    const { leave, delayLeave } = transition
    const performLeave = () => leave(el!, performRemove)
    // 推遲 leave 動(dòng)畫(huà)
    if (delayLeave) {
      delayLeave(vnode.el!, performRemove, performLeave)
    } else {
      performLeave()
    }
  } else {
    // 執(zhí)行
    performRemove()
  }
}

removeFragment

直接遍歷移除所有包含的節(jié)點(diǎn),這一點(diǎn)與移除靜態(tài)節(jié)點(diǎn)十分相似。

const removeFragment = (cur: RendererNode, end: RendererNode) => {
  // For fragments, directly remove all contained DOM nodes.
  // (fragment child nodes cannot have transition)
  let next
  while (cur !== end) {
    next = hostNextSibling(cur)!
    hostRemove(cur)
    cur = next
  }
  hostRemove(end)
}

unmountComponent

對(duì)于組件的卸載,步驟稍微多一點(diǎn)。畢竟除了要遍歷卸載子組件樹(shù),要處理組件的鉤子函數(shù),甚至考慮異步組件。

const unmountComponent = (
  instance: ComponentInternalInstance,
  parentSuspense: SuspenseBoundary | null,
  doRemove?: boolean
) => {
  if (__DEV__ && instance.type.__hmrId) {
    unregisterHMR(instance)
  }
  const { bum, scope, update, subTree, um } = instance
  // 調(diào)用 beforeUnmounted 鉤子
  // beforeUnmount hook
  if (bum) {
    invokeArrayFns(bum)
  }
  if (
    __COMPAT__ &&
    isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
  ) {
    instance.emit('hook:beforeDestroy')
  }
  // 停止副作用
  // stop effects in component scope
  scope.stop()
  // 關(guān)閉 update,卸載子組件樹(shù)
  // update may be null if a component is unmounted before its async
  // setup has resolved.
  if (update) {
    // so that scheduler will no longer invoke it
    update.active = false
    unmount(subTree, instance, parentSuspense, doRemove)
  }
  // 調(diào)用unmounted鉤子
  // unmounted hook
  if (um) {
    queuePostRenderEffect(um, parentSuspense)
  }
  // 向后兼容:destroyed 鉤子
  if (
    __COMPAT__ &&
    isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
  ) {
    queuePostRenderEffect(
      () => instance.emit('hook:destroyed'),
      parentSuspense
    )
  }
  // 更改狀態(tài)為已卸載
  queuePostRenderEffect(() => {
    instance.isUnmounted = true
  }, parentSuspense)
  // 處理<Suspense>
  // A component with async dep inside a pending suspense is unmounted before
  // its async dep resolves. This should remove the dep from the suspense, and
  // cause the suspense to resolve immediately if that was the last dep.
  if (
    __FEATURE_SUSPENSE__ &&
    parentSuspense &&
    parentSuspense.pendingBranch &&
    !parentSuspense.isUnmounted &&
    instance.asyncDep &&
    !instance.asyncResolved &&
    instance.suspenseId === parentSuspense.pendingId
  ) {
    parentSuspense.deps--
    if (parentSuspense.deps === 0) {
      parentSuspense.resolve()
    }
  }
  if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
    devtoolsComponentRemoved(instance)
  }
}

unmountChildren

卸載子節(jié)點(diǎn),遍歷遞歸unmount方法進(jìn)行卸載。

const unmountChildren: UnmountChildrenFn = (
  children,
  parentComponent,
  parentSuspense,
  doRemove = false,
  optimized = false,
  start = 0
) => {
  for (let i = start; i < children.length; i++) {
    unmount(children[i], parentComponent, parentSuspense, doRemove, optimized)
  }
}

小結(jié)

render只是個(gè)引子,絕大部分功能如節(jié)點(diǎn)掛載、節(jié)點(diǎn)更新都被patch涵蓋了。diff算法在同層級(jí)進(jìn)行遍歷比較,核心內(nèi)容都在patchKeyedChildren中,首尾節(jié)點(diǎn)各自循環(huán)一輪,對(duì)于中間的節(jié)點(diǎn),則利用Map來(lái)映射key和節(jié)點(diǎn)在新子節(jié)點(diǎn)組中的index,再遍歷剩余的舊子節(jié)點(diǎn)組,在Map中找相同的key里確定這個(gè)舊節(jié)點(diǎn)是否可復(fù)用。沒(méi)有key的情況則使用patchUnkeyedChildren進(jìn)行diff,簡(jiǎn)單粗暴。

以上就是Vue3源碼通過(guò)render patch 了解diff的詳細(xì)內(nèi)容,更多關(guān)于Vue3 render patch了解diff的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue3中實(shí)現(xiàn)雙向數(shù)據(jù)綁定的方法

    vue3中實(shí)現(xiàn)雙向數(shù)據(jù)綁定的方法

    Vue3中,雙向數(shù)據(jù)綁定主要通過(guò)v-model指令實(shí)現(xiàn),v-model是一個(gè)語(yǔ)法糖,結(jié)合了v-bind和v-on指令來(lái)實(shí)現(xiàn)數(shù)據(jù)的雙向綁定,它在內(nèi)部做了綁定數(shù)據(jù)和監(jiān)聽(tīng)輸入事件兩件事,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • 詳解vue-validator(vue驗(yàn)證器)

    詳解vue-validator(vue驗(yàn)證器)

    本篇文章主要介紹了vue-validator(vue驗(yàn)證器),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • Vue使用mixins實(shí)現(xiàn)壓縮圖片代碼

    Vue使用mixins實(shí)現(xiàn)壓縮圖片代碼

    本篇文章主要介紹了Vue使用mixins實(shí)現(xiàn)壓縮圖片代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • 關(guān)于Element-ui中el-table出現(xiàn)的表格錯(cuò)位問(wèn)題解決

    關(guān)于Element-ui中el-table出現(xiàn)的表格錯(cuò)位問(wèn)題解決

    使用ElementUI的el-table后,偶然發(fā)現(xiàn)出現(xiàn)行列錯(cuò)位、對(duì)不齊問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于Element-ui中el-table出現(xiàn)的表格錯(cuò)位問(wèn)題解決的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • Vue el使用el-checkbox-group復(fù)選框進(jìn)行單選框方式

    Vue el使用el-checkbox-group復(fù)選框進(jìn)行單選框方式

    這篇文章主要介紹了Vue el使用el-checkbox-group復(fù)選框進(jìn)行單選框方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue如何自定義事件傳參

    vue如何自定義事件傳參

    這篇文章主要介紹了vue如何自定義事件傳參,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • uniapp頁(yè)面完成水印添加功能代碼示例(自定義文字)

    uniapp頁(yè)面完成水印添加功能代碼示例(自定義文字)

    這篇文章主要介紹了uniapp頁(yè)面完成水印添加功能(自定義文字)的相關(guān)資料,包括如何編寫(xiě)頁(yè)面代碼、數(shù)據(jù)代碼以及如何展示效果圖,通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-01-01
  • vue自定義標(biāo)簽和單頁(yè)面多路由的實(shí)現(xiàn)代碼

    vue自定義標(biāo)簽和單頁(yè)面多路由的實(shí)現(xiàn)代碼

    這篇文章主要介紹了vue自定義標(biāo)簽和單頁(yè)面多路由的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • keep-Alive搭配vue-router實(shí)現(xiàn)緩存頁(yè)面效果的示例代碼

    keep-Alive搭配vue-router實(shí)現(xiàn)緩存頁(yè)面效果的示例代碼

    這篇文章主要介紹了keep-Alive搭配vue-router實(shí)現(xiàn)緩存頁(yè)面效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • vue中el-tab如何點(diǎn)擊不同標(biāo)簽觸發(fā)不同函數(shù)的實(shí)現(xiàn)

    vue中el-tab如何點(diǎn)擊不同標(biāo)簽觸發(fā)不同函數(shù)的實(shí)現(xiàn)

    el-tab本身的功能是點(diǎn)擊之后切換不同頁(yè),本文主要介紹了vue中el-tab如何點(diǎn)擊不同標(biāo)簽觸發(fā)不同函數(shù)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03

最新評(píng)論

啪啪啪操人视频在线播放| 玩弄人妻熟妇性色av少妇| 日本一区精品视频在线观看| 天天操天天爽天天干| 国产激情av网站在线观看| xxx日本hd高清| 亚洲区欧美区另类最新章节| 免费在线观看污污视频网站| 亚洲一级av大片免费观看| 91‖亚洲‖国产熟女| 黑人巨大精品欧美视频| 91精品高清一区二区三区| 深夜男人福利在线观看| 亚洲成人av一区在线| 伊人开心婷婷国产av| 亚洲av男人天堂久久| 97人妻人人澡爽人人精品| 亚洲激情偷拍一区二区| 91人妻精品一区二区久久| 免费观看理论片完整版| 激情五月婷婷综合色啪| 九一传媒制片厂视频在线免费观看 | 日本一二三中文字幕| 中文字幕一区的人妻欧美日韩| 精品一区二区三区三区88| aⅴ精产国品一二三产品| 18禁美女黄网站色大片下载| 99精品视频之69精品视频 | 色噜噜噜噜18禁止观看| 亚洲老熟妇日本老妇| 18禁免费av网站| 大鸡巴操b视频在线| 2022国产综合在线干| 女蜜桃臀紧身瑜伽裤| 亚洲 色图 偷拍 欧美| 久久久91蜜桃精品ad| 黄片大全在线观看观看| 老司机在线精品福利视频| 精品视频中文字幕在线播放| 久久免费看少妇高潮完整版| 中文字幕人妻三级在线观看| 激情色图一区二区三区| 啊啊好大好爽啊啊操我啊啊视频| 人妻久久无码中文成人| 51国产偷自视频在线播放| 亚洲国产最大av综合| 一区二区在线观看少妇| av视屏免费在线播放| 日本黄在免费看视频| 91av中文视频在线| 丝袜肉丝一区二区三区四区在线 | 色婷婷综合激情五月免费观看| 国产性感美女福利视频| 久久精品亚洲成在人线a| 人妻丝袜榨强中文字幕| 人妻最新视频在线免费观看| 日日夜夜狠狠干视频| 婷婷五月亚洲综合在线| 亚洲国产美女一区二区三区软件| 免费看美女脱光衣服的视频| 大黑人性xxxxbbbb| 天天日天天玩天天摸| 亚洲 自拍 色综合图| 第一福利视频在线观看| 亚洲欧美精品综合图片小说| 国产中文字幕四区在线观看| 人人超碰国字幕观看97| 色综合久久无码中文字幕波多| 国产黄色片在线收看| 天天摸天天日天天操| 75国产综合在线视频| 精品一区二区亚洲欧美| 亚洲激情唯美亚洲激情图片| 在线观看免费视频色97| 欧美怡红院视频在线观看| 国产中文精品在线观看| 一区二区三区久久久91| 久久久噜噜噜久久熟女av| 亚洲一级特黄特黄黄色录像片| 亚洲一区二区三区av网站| 五月天中文字幕内射| 老司机免费福利视频网| 黄网十四区丁香社区激情五月天| 日韩不卡中文在线视频网站| 一级黄片大鸡巴插入美女| 在线观看一区二区三级| 99热碰碰热精品a中文| 亚洲 自拍 色综合图| 亚洲护士一区二区三区| av天堂中文免费在线| 国产实拍勾搭女技师av在线| 中文字幕在线一区精品| av中文字幕在线导航| 亚洲一区二区三区久久午夜 | av完全免费在线观看av| 2020av天堂网在线观看| av俺也去在线播放| 青草久久视频在线观看| 亚洲免费国产在线日韩| 偷拍自拍亚洲美腿丝袜| 一个色综合男人天堂| 超鹏97历史在线观看| 自拍偷拍亚洲精品第2页| 色婷婷六月亚洲综合香蕉| 日韩伦理短片在线观看| 亚洲 中文字幕在线 日韩| 清纯美女在线观看国产| 欧美成一区二区三区四区| 天天日天天干天天插舔舔| 黄片色呦呦视频免费看| 最近的中文字幕在线mv视频| 欧美精产国品一二三产品价格| 婷婷久久久综合中文字幕| 天堂av中文在线最新版| 亚洲熟女久久久36d| 日韩在线视频观看有码在线| 蜜臀av久久久久久久| 国产a级毛久久久久精品| 亚洲成人av一区久久| 国产精品成人xxxx| 91福利在线视频免费观看| 中文字幕无码日韩专区免费| 亚洲无码一区在线影院| 亚洲一区二区三区在线高清| 九九视频在线精品播放| 人妻少妇精品久久久久久| 不卡日韩av在线观看| 亚洲av香蕉一区区二区三区犇| 99精品国自产在线人| 91色秘乱一区二区三区| 三级av中文字幕在线观看| 亚洲熟妇无码一区二区三区| 丝袜国产专区在线观看| 婷婷久久久久深爱网| 国产又粗又硬又猛的毛片视频| 亚洲高清国产一区二区三区| 亚洲av日韩av网站| a v欧美一区=区三区| 天天操天天操天天碰| 福利在线视频网址导航| 久久久久久性虐视频| mm131美女午夜爽爽爽| 只有精品亚洲视频在线观看| 不卡日韩av在线观看| 国产高清97在线观看视频| 日韩av有码一区二区三区4 | 不卡精品视频在线观看| 日本性感美女三级视频| 日韩无码国产精品强奸乱伦| 欧美日本在线视频一区| 亚洲人妻国产精品综合| av男人天堂狠狠干| 国产视频网站一区二区三区| 日韩欧美在线观看不卡一区二区 | 亚洲高清国产拍青青草原| 日本少妇的秘密免费视频| 日韩精品中文字幕在线| 久久午夜夜伦痒痒想咳嗽P| 国产露脸对白在线观看| 亚洲自拍偷拍综合色| 精品黑人一区二区三区久久国产| 日韩伦理短片在线观看| 欧美老妇精品另类不卡片| 成人福利视频免费在线| 亚洲免费福利一区二区三区| 国产日本欧美亚洲精品视| 中国老熟女偷拍第一页| 国产成人小视频在线观看无遮挡| 成人免费公开视频无毒| 91自产国产精品视频| 午夜国产免费福利av| 国产黑丝高跟鞋视频在线播放| 色综合天天综合网国产成人| 18禁污污污app下载| 成人av天堂丝袜在线观看| 色综合久久五月色婷婷综合| 很黄很污很色的午夜网站在线观看| 精品成人午夜免费看| 99re久久这里都是精品视频| 快插进小逼里大鸡吧视频| 秋霞午夜av福利经典影视| 国产品国产三级国产普通话三级| 99精品免费观看视频| 欧美国产亚洲中英文字幕| 六月婷婷激情一区二区三区| av手机免费在线观看高潮| 欧美激情精品在线观看| 国产第一美女一区二区三区四区| 91国内视频在线观看| 无忧传媒在线观看视频| 国产V亚洲V天堂无码欠欠| 大鸡巴操娇小玲珑的女孩逼| 91国内精品久久久久精品一| 中文字幕一区二区人妻电影冢本| 性感美女高潮视频久久久| 国产极品美女久久久久久| 中文字幕免费福利视频6| 福利片区一区二体验区| 久久永久免费精品人妻专区| 最新91九色国产在线观看| 国产av一区2区3区| 性色av一区二区三区久久久 | 三上悠亚和黑人665番号| 18禁污污污app下载| 宅男噜噜噜666免费观看| 五十路熟女人妻一区二区9933| 中文字幕高清免费在线人妻| 国产丰满熟女成人视频| 快点插进来操我逼啊视频| 男人靠女人的逼视频| 色婷婷六月亚洲综合香蕉| 91试看福利一分钟| 亚洲中文字字幕乱码| 午夜精品久久久久久99热| 亚洲一区二区三区精品视频在线 | 国产麻豆剧传媒精品国产av蜜桃| 日本www中文字幕| 97欧洲一区二区精品免费| 免费黄高清无码国产| 免费费一级特黄真人片| 好男人视频在线免费观看网站| 色综合久久无码中文字幕波多| 2025年人妻中文字幕乱码在线| 欧美激情精品在线观看| 国产综合视频在线看片| 97人妻无码AV碰碰视频| 人人爱人人妻人人澡39| 国产精品人妻熟女毛片av久| 2022天天干天天操| 护士特殊服务久久久久久久| xxx日本hd高清| 超黄超污网站在线观看| 乱亲女秽乱长久久久| 成人福利视频免费在线| 日韩人妻在线视频免费| 91亚洲精品干熟女蜜桃频道| 日韩欧美高清免费在线| 午夜国产福利在线观看| 亚洲日本一区二区三区| 丝袜亚洲另类欧美变态| 玩弄人妻熟妇性色av少妇| 人人爱人人妻人人澡39| 都市家庭人妻激情自拍视频| 男人的天堂一区二区在线观看| 免费男阳茎伸入女阳道视频 | 亚洲欧美自拍另类图片| 欧美精品 日韩国产| 天天日天天添天天爽| 亚洲午夜电影在线观看| av手机免费在线观看高潮| 天堂av狠狠操蜜桃| 国产精彩福利精品视频| 肏插流水妹子在线乐播下载| 精品一区二区亚洲欧美| 91久久人澡人人添人人爽乱| 精品一区二区三区在线观看| 日韩精品中文字幕在线| 深夜男人福利在线观看| 亚洲国产欧美一区二区丝袜黑人| 狠狠嗨日韩综合久久| 夜色17s精品人妻熟女| 精品黑人巨大在线一区| 五月天色婷婷在线观看视频免费| 欧洲日韩亚洲一区二区三区| 3D动漫精品啪啪一区二区下载| 人妻激情图片视频小说| 国产一区成人在线观看视频| 成年人免费看在线视频| 亚洲综合一区成人在线| 在线免费观看av日韩| 性感美女诱惑福利视频| 国产美女午夜福利久久| 欧美精品资源在线观看| 日韩av有码一区二区三区4 | 成人乱码一区二区三区av| 日本人竟这样玩学生妹| 男人和女人激情视频| 日韩欧美制服诱惑一区在线| 日本韩国亚洲综合日韩欧美国产 | 啊啊好大好爽啊啊操我啊啊视频| 亚洲伊人色一综合网| 蜜桃精品久久久一区二区| 在线免费观看日本片| 国产乱子伦一二三区| 五十路熟女人妻一区二| 亚洲精品乱码久久久久久密桃明| 91精品高清一区二区三区| 日本免费视频午夜福利视频| av在线资源中文字幕| 国产麻豆精品人妻av| 中文字幕 码 在线视频| 国产亚洲欧美视频网站| 亚洲国产欧美一区二区三区…| 在线国产日韩欧美视频| 亚洲一区av中文字幕在线观看| 精品亚洲中文字幕av| 天天色天天舔天天射天天爽| 超级碰碰在线视频免费观看| 中文字幕在线永久免费播放| 国产熟妇乱妇熟色T区| 中文字幕一区二区亚洲一区| 亚洲2021av天堂| 9l人妻人人爽人人爽| 人妻少妇中文有码精品| 色哟哟国产精品入口| 天天操,天天干,天天射| 日本后入视频在线观看| 日本www中文字幕| 国产夫妻视频在线观看免费 | 97国产福利小视频合集| 久久久久久国产精品| 天天干天天操天天爽天天摸| 91精品高清一区二区三区| 精品一区二区三区在线观看| 精品欧美一区二区vr在线观看| 久久农村老妇乱69系列| 视频一区 二区 三区 综合| 国产麻豆剧传媒精品国产av蜜桃| 国产+亚洲+欧美+另类| 婷婷综合蜜桃av在线| 绯色av蜜臀vs少妇| 99热久久极品热亚洲| 日本韩国亚洲综合日韩欧美国产| 熟女91pooyn熟女| 啊啊好大好爽啊啊操我啊啊视频 | 狠狠地躁夜夜躁日日躁| 岛国免费大片在线观看| 精品黑人一区二区三区久久国产| 欧美偷拍亚洲一区二区| 日日摸夜夜添夜夜添毛片性色av| 日噜噜噜夜夜噜噜噜天天噜噜噜| 天天草天天色天天干| 国产成人精品福利短视频| a v欧美一区=区三区| www日韩毛片av| 亚洲黄色av网站免费播放| 成人蜜臀午夜久久一区| 国产污污污污网站在线| 日本人妻精品久久久久久| 国产久久久精品毛片| 日日夜夜狠狠干视频| eeuss鲁片一区二区三区| 93人妻人人揉人人澡人人| 青青青视频自偷自拍38碰| 中国熟女一区二区性xx| 男生用鸡操女生视频动漫| 亚洲人妻av毛片在线| 色综合色综合色综合色| 亚洲国际青青操综合网站| 亚洲欧美自拍另类图片| 扒开让我视频在线观看| 精品日产卡一卡二卡国色天香| 天天日天天干天天插舔舔| 日本一二三区不卡无| 无码日韩人妻精品久久| 爆乳骚货内射骚货内射在线| 午夜极品美女福利视频| 中文字幕在线免费第一页| 亚洲精品一区二区三区老狼| 亚洲欧美激情国产综合久久久| 国产精品久久综合久久| 年轻的人妻被夫上司侵犯| 亚洲综合另类精品小说| 国产妇女自拍区在线观看| www日韩a级s片av| wwwxxx一级黄色片| 噜噜色噜噜噜久色超碰| 亚洲午夜高清在线观看| jiujiure精品视频在线| 啪啪啪啪啪啪啪免费视频| 欧美黄片精彩在线免费观看 | 亚洲欧美成人综合在线观看| 国产精品手机在线看片| 亚洲一区自拍高清免费视频| 精品一线二线三线日本| 欧美一区二区中文字幕电影 | 国产视频网站国产视频| 免费高清自慰一区二区三区网站| 国产精品国色综合久久| 大香蕉玖玖一区2区| 精品黑人一区二区三区久久国产| 少妇人妻真实精品视频| 在线观看免费视频网| 欧美性感尤物人妻在线免费看| 亚洲人一区二区中文字幕| 亚洲人妻国产精品综合| 婷婷五月亚洲综合在线| 亚洲高清国产拍青青草原| 欧美成人一二三在线网| 欧美日韩人妻久久精品高清国产| 韩国亚洲欧美超一级在线播放视频| 91国产在线免费播放| 午夜精品一区二区三区城中村| 在线免费观看国产精品黄色| 综合精品久久久久97| 亚洲乱码中文字幕在线| 久碰精品少妇中文字幕av| 狠狠躁夜夜躁人人爽天天久天啪| 91人妻精品一区二区在线看| 521精品视频在线观看| 亚洲少妇人妻无码精品| 狠狠嗨日韩综合久久| 二区中出在线观看老师| 精品av国产一区二区三区四区| www,久久久,com| 欧美日本在线视频一区| 男人和女人激情视频| 亚洲国产成人在线一区| 亚洲国产第一页在线观看| 99热久久极品热亚洲| 中文字幕一区的人妻欧美日韩| 夜色撩人久久7777| 同居了嫂子在线播高清中文| 免费在线福利小视频| 亚洲1069综合男同| 亚洲最大黄了色网站| 亚洲综合另类精品小说| 久草视频首页在线观看| 欧美熟妇一区二区三区仙踪林| 啊慢点鸡巴太大了啊舒服视频| 91免费福利网91麻豆国产精品 | 又黄又刺激的午夜小视频| 国产超码片内射在线| 五月婷婷在线观看视频免费 | 午夜精品在线视频一区| 日本女大学生的黄色小视频| 亚洲中文字字幕乱码| 亚洲高清视频在线不卡| 免费人成黄页网站在线观看国产| 国产在线免费观看成人| 国产精品成久久久久三级蜜臀av | 一色桃子人妻一区二区三区| 国产三级精品三级在线不卡| 人妻久久无码中文成人| 人妻少妇亚洲精品中文字幕| 91色老99久久九九爱精品| 亚洲欧洲一区二区在线观看| 5528327男人天堂| 欧美在线精品一区二区三区视频 | 最新97国产在线视频| 婷婷午夜国产精品久久久| 天堂va蜜桃一区入口| 国产精品中文av在线播放 | 任你操视频免费在线观看| 91色老99久久九九爱精品| 国产97在线视频观看| 秋霞午夜av福利经典影视| 91免费观看在线网站 | 亚洲欧美成人综合在线观看| 国产一区二区三免费视频| 98精产国品一二三产区区别| 操日韩美女视频在线免费看| 青青青青青青青青青青草青青| 国产精品自拍在线视频| av中文字幕电影在线看| 在线视频国产欧美日韩| 日本裸体熟妇区二区欧美| 中文字幕+中文字幕| 久草视频在线看免费| 中文字幕av第1页中文字幕| 日韩剧情片电影在线收看| 亚洲欧美人精品高清| 国产一区二区久久久裸臀| 色哟哟国产精品入口| av一区二区三区人妻| 亚洲日本一区二区久久久精品| 亚洲区欧美区另类最新章节| 18禁网站一区二区三区四区| 亚洲欧美在线视频第一页| sspd152中文字幕在线| yy6080国产在线视频| 一级黄片久久久久久久久| 国产精品熟女久久久久浪潮| 日韩在线视频观看有码在线| 快点插进来操我逼啊视频| 天天日天天做天天日天天做| 骚逼被大屌狂草视频免费看| 福利国产视频在线观看| 2025年人妻中文字幕乱码在线| 免费无码人妻日韩精品一区二区 | 3344免费偷拍视频| 在线观看欧美黄片一区二区三区| 亚洲欧美激情中文字幕| 黄色片一级美女黄色片| 97香蕉碰碰人妻国产樱花| 国产精品国产三级国产精东 | 2021国产一区二区| 在线免费91激情四射 | 成人av亚洲一区二区| 国产精品国产三级国产午| 又粗又硬又猛又黄免费30| 欧美成人精品欧美一级黄色| 啪啪啪啪啪啪啪啪啪啪黄色| 日韩人妻丝袜中文字幕| 亚洲午夜电影在线观看| 午夜场射精嗯嗯啊啊视频| 久久精品国产999| 超碰97人人做人人爱| 精品av国产一区二区三区四区| 38av一区二区三区| xxx日本hd高清| 在线免费91激情四射| 偷拍自拍国产在线视频| 少妇人妻二三区视频| 国产自拍在线观看成人| 亚洲熟妇久久无码精品| 免费十精品十国产网站| 伊人综合免费在线视频| 天天日天天鲁天天操| 久久精品久久精品亚洲人| 美女 午夜 在线视频| 天天射夜夜操狠狠干| 早川濑里奈av黑人番号| 欧美成人黄片一区二区三区| 97年大学生大白天操逼| 亚洲精品在线资源站| 久久久久久99国产精品| 懂色av之国产精品| 天干天天天色天天日天天射| 亚洲精品久久视频婷婷| aⅴ精产国品一二三产品| 水蜜桃国产一区二区三区| 亚洲成人午夜电影在线观看| 青青操免费日综合视频观看| 日韩成人综艺在线播放| 91免费黄片可看视频| 免费在线黄色观看网站| 婷婷五月亚洲综合在线| 久久热这里这里只有精品| 精品亚洲国产中文自在线| 91精品国产高清自在线看香蕉网| 国产麻豆91在线视频| 韩国三级aaaaa高清视频| 沙月文乃人妻侵犯中文字幕在线| 一级a看免费观看网站| 亚洲av人人澡人人爽人人爱| 韩国AV无码不卡在线播放 | 一区二区在线观看少妇| 人人爽亚洲av人人爽av| 福利午夜视频在线合集| 色综合天天综合网国产成人 | 亚洲人一区二区中文字幕| 黄色资源视频网站日韩| 成人综合亚洲欧美一区| 精品美女福利在线观看| 日本韩国在线观看一区二区| 女警官打开双腿沦为性奴| 大香蕉日本伊人中文在线| 少妇人妻久久久久视频黄片| 亚洲欧美自拍另类图片| 欧美日韩中文字幕欧美| 人妻素人精油按摩中出| 亚洲国产美女一区二区三区软件| 最新激情中文字幕视频| 国产三级影院在线观看| 日韩一个色综合导航| 一区二区三区综合视频| 中文字幕乱码人妻电影| 亚洲成人av一区在线| 不卡一不卡二不卡三| 丰满少妇人妻xxxxx| 黄片色呦呦视频免费看| 亚洲变态另类色图天堂网| 成人性爱在线看四区| 日日爽天天干夜夜操| 国产精品一区二区av国| 噜噜色噜噜噜久色超碰| 日韩av中文在线免费观看| 成人30分钟免费视频| 欧洲黄页网免费观看| 中文亚洲欧美日韩无线码| 天天日天天干天天舔天天射| 超碰97免费人妻麻豆 | 亚洲av成人免费网站| 国产精品自拍在线视频| 男人操女人逼逼视频网站| 国产夫妻视频在线观看免费| 欧美伊人久久大香线蕉综合| 三级等保密码要求条款| 日本少妇精品免费视频| 亚洲免费va在线播放| 日本特级片中文字幕| 青青青青视频在线播放| 日本脱亚入欧是指什么| 福利视频广场一区二区| 91老师蜜桃臀大屁股| 国产精品三级三级三级| 国产精品国产三级麻豆| 美女av色播在线播放| av老司机精品在线观看| 久草极品美女视频在线观看| 午夜精品福利91av| 久久人人做人人妻人人玩精品vr| 九九视频在线精品播放| 青青尤物在线观看视频网站| 日本性感美女写真视频| 亚洲精品精品国产综合| 亚洲国产在线精品国偷产拍| weyvv5国产成人精品的视频| 天天插天天狠天天操| 18禁无翼鸟成人在线| 亚洲人一区二区中文字幕| 鸡巴操逼一级黄色气| 国产av一区2区3区| 喷水视频在线观看这里只有精品| 亚洲免费va在线播放| 久久www免费人成一看片| 中文字幕免费福利视频6| 东游记中文字幕版哪里可以看到| 在线免费视频 自拍| 国产成人精品久久二区91| 人妻激情图片视频小说| 人妻在线精品录音叫床| 人妻少妇中文有码精品| 午夜毛片不卡在线看| 天堂av在线官网中文| 3337p日本欧洲大胆色噜噜| 国产视频一区在线观看| 国产精品一二三不卡带免费视频| 超级碰碰在线视频免费观看| 欧美精品久久久久久影院| 午夜91一区二区三区| 成人福利视频免费在线| 国产在线91观看免费观看| 亚洲精品无码久久久久不卡| www天堂在线久久| 直接能看的国产av| 人妻久久久精品69系列| 不卡精品视频在线观看| 婷婷午夜国产精品久久久| 色呦呦视频在线观看视频| 欧美成人综合视频一区二区| 11久久久久久久久久久| 91极品新人『兔兔』精品新作| 亚洲熟女综合色一区二区三区四区| 在线观看的黄色免费网站| 黄色三级网站免费下载| 精品国产污污免费网站入口自| 精品国产午夜视频一区二区| 国产精品久久久久久久精品视频| 五月婷婷在线观看视频免费| 91国产在线视频免费观看| 51国产成人精品视频| 日本av熟女在线视频| 国产欧美精品一区二区高清| 亚洲国产最大av综合| 久久丁香婷婷六月天| 骚逼被大屌狂草视频免费看| 在线观看视频污一区| av天堂加勒比在线| 青青青青青操视频在线观看| 色狠狠av线不卡香蕉一区二区| 亚洲老熟妇日本老妇| 美女福利视频网址导航| 欧洲欧美日韩国产在线| 熟女妇女老妇一二三区| 中文字幕亚洲中文字幕| 免费人成黄页网站在线观看国产| 天天操夜夜操天天操天天操| 亚洲男人让女人爽的视频| 乱亲女秽乱长久久久| 国产又粗又猛又爽又黄的视频美国| 中国把吊插入阴蒂的视频| 特级欧美插插插插插bbbbb| 成熟丰满熟妇高潮xx×xx| 欧美成人综合色在线噜噜| 国产真实灌醉下药美女av福利| 国产污污污污网站在线| 亚洲自拍偷拍精品网| 天天躁夜夜躁日日躁a麻豆| 亚洲伊人色一综合网| 亚洲熟妇无码一区二区三区| 人妻少妇性色欲欧美日韩| 在线不卡成人黄色精品| 青青青国产免费视频| 91九色国产porny蝌蚪| 日本在线不卡免费视频| 福利视频一区二区三区筱慧| 国产97在线视频观看| 青草久久视频在线观看| 十八禁在线观看地址免费| 美女视频福利免费看| 超碰公开大香蕉97| 一个色综合男人天堂| 久草视频在线一区二区三区资源站| 自拍偷拍 国产资源| 久草视频首页在线观看| 免费观看丰满少妇做受| 天天射夜夜操狠狠干| av在线免费观看亚洲天堂| 男人操女人逼逼视频网站| 亚洲伊人av天堂有码在线| 国产一线二线三线的区别在哪| 国产极品精品免费视频| 国产极品精品免费视频 | 中文字幕+中文字幕| 国产视频一区在线观看| 熟女视频一区,二区,三区| 日日日日日日日日夜夜夜夜夜夜| 亚洲av日韩av第一区二区三区| 欧美特级特黄a大片免费| 精品美女在线观看视频在线观看 | 青青青青青青草国产| 青青草原色片网站在线观看| 精品av久久久久久久| 精品久久婷婷免费视频| 三级等保密码要求条款| wwwxxx一级黄色片| 精品国产污污免费网站入口自 | 欧美中文字幕一区最新网址| 国产真实灌醉下药美女av福利| 2022精品久久久久久中文字幕| 国产自拍在线观看成人| 特级欧美插插插插插bbbbb| 亚洲人妻av毛片在线| 热思思国产99re| 日韩伦理短片在线观看| 免费看国产av网站| 黑人解禁人妻叶爱071| 果冻传媒av一区二区三区| 男人的网址你懂的亚洲欧洲av| 在线成人日韩av电影| 亚洲一级特黄特黄黄色录像片| 亚洲专区激情在线观看视频| 国产亚州色婷婷久久99精品| av老司机精品在线观看| 99久久99一区二区三区| 伊拉克及约旦宣布关闭领空| 国产精品伦理片一区二区| 丁香花免费在线观看中文字幕| 91高清成人在线视频| 国产欧美日韩在线观看不卡| 久草视频在线免播放| 在线免费观看日本片| 在线观看免费视频网| 91精品国产高清自在线看香蕉网 | 国产精品自偷自拍啪啪啪| 人妻爱爱 中文字幕| 午夜频道成人在线91| 中文字幕亚洲久久久| av在线观看网址av| 99国内小视频在现欢看| 家庭女教师中文字幕在线播放| 国产美女精品福利在线| 亚洲国产美女一区二区三区软件| 亚洲无线观看国产高清在线| 青青青艹视频在线观看| 欧美视频不卡一区四区| 亚洲美女高潮喷浆视频| 91免费放福利在线观看| 午夜毛片不卡免费观看视频| 一区二区三区欧美日韩高清播放| 肏插流水妹子在线乐播下载| 亚洲免费视频欧洲免费视频| 成年人啪啪视频在线观看| 国产美女一区在线观看| 欧美熟妇一区二区三区仙踪林| 青草亚洲视频在线观看| 欧美成人小视频在线免费看| 99精品久久久久久久91蜜桃| 国产chinesehd精品麻豆| 欧美黑人与人妻精品| 成人av亚洲一区二区| 自拍偷拍日韩欧美一区二区| 日韩激情文学在线视频| 55夜色66夜色国产精品站| 精品一区二区三区在线观看| 亚洲一区二区三区uij| 91国内视频在线观看| av手机免费在线观看高潮| 午夜激情精品福利视频| 亚洲欧美一区二区三区爱爱动图| 中文字幕一区的人妻欧美日韩| 超污视频在线观看污污污| 欧美精产国品一二三区| 国产乱子伦精品视频潮优女| 精内国产乱码久久久久久| 97人妻夜夜爽二区欧美极品| 人人人妻人人澡人人| 亚洲一级特黄特黄黄色录像片| 日韩伦理短片在线观看| 天天干天天操天天爽天天摸| 欧美性感尤物人妻在线免费看| 黄色的网站在线免费看| 2022国产精品视频| 天天色天天操天天透| 国产精品黄色的av| 亚洲人人妻一区二区三区| 91免费观看在线网站 | 天天干天天搞天天摸| 精品一区二区三区欧美| 久久久久久99国产精品| 日韩美女福利视频网| 动漫黑丝美女的鸡巴| 天堂av狠狠操蜜桃| 青青草精品在线视频观看| 欧美日韩国产一区二区三区三州 | 欧美地区一二三专区| 偷青青国产精品青青在线观看 | 瑟瑟视频在线观看免费视频| 欧美性感尤物人妻在线免费看| 人人妻人人人操人人人爽| 日本三极片视频网站观看| 亚洲国产成人无码麻豆艾秋| 97欧洲一区二区精品免费| 爆乳骚货内射骚货内射在线| 特一级特级黄色网片| 国产精品黄大片在线播放| 57pao国产一区二区| 亚洲蜜臀av一区二区三区九色| 日本免费一级黄色录像| 免费在线看的黄网站| 亚洲男人让女人爽的视频| 亚洲福利天堂久久久久久| 亚洲精品在线资源站| 人妻在线精品录音叫床| 在线国产日韩欧美视频| 99一区二区在线观看| 日韩中文字幕福利av| 蜜桃色婷婷久久久福利在线| 中文字幕人妻三级在线观看| 精品一区二区三区三区色爱| 黄色无码鸡吧操逼视频| 亚洲的电影一区二区三区| 大鸡吧插入女阴道黄色片| 漂亮 人妻被中出中文| 成人资源在线观看免费官网| 天天干狠狠干天天操| 国产精品熟女久久久久浪潮| 99久久成人日韩欧美精品| 成人性黑人一级av| 亚洲2021av天堂| 偷拍3456eee| 日本五十路熟新垣里子| 色噜噜噜噜18禁止观看| 天天日天天干天天干天天日| 免费在线看的黄片视频| 亚洲av黄色在线网站| 激情国产小视频在线| 亚洲最大免费在线观看| 亚洲嫩模一区二区三区| 中文字幕+中文字幕| 揄拍成人国产精品免费看视频| 伊人综合aⅴ在线网| 国产白嫩美女一区二区| 日本女大学生的黄色小视频| 青青青青青操视频在线观看| 成年女人免费播放视频| 一区二区视频视频视频| 国产精品一区二区三区蜜臀av| 国产乱子伦精品视频潮优女| 香蕉片在线观看av| 最新欧美一二三视频| 中文字幕一区二区三区人妻大片| 啊慢点鸡巴太大了啊舒服视频| 欧美性受xx黑人性猛交| av无限看熟女人妻另类av| 亚洲黄色av网站免费播放| 自拍偷拍 国产资源| 五十路熟女av天堂| 欧美第一页在线免费观看视频| 在线观看欧美黄片一区二区三区| 粉嫩av蜜乳av蜜臀| 中文字幕一区二区亚洲一区| 一区二区三区综合视频| 天天操夜夜骑日日摸| 中国熟女一区二区性xx| 日本高清在线不卡一区二区| 日韩欧美中文国产在线| 影音先锋女人av噜噜色| 北条麻妃肉色丝袜视频| 2o22av在线视频| 成人乱码一区二区三区av| 国产妇女自拍区在线观看| av天堂中文字幕最新| 嫩草aⅴ一区二区三区| 国产三级片久久久久久久| 国产视频在线视频播放| 9久在线视频只有精品| 亚洲国产成人最新资源| 精品久久婷婷免费视频| 黑人3p华裔熟女普通话| 91中文字幕最新合集| 伊人网中文字幕在线视频| 日韩二区视频一线天婷婷五| 亚洲av极品精品在线观看| 粉嫩欧美美人妻小视频| 国产黄色a级三级三级三级| 91传媒一区二区三区| 2022中文字幕在线| 后入美女人妻高清在线| 蜜桃视频在线欧美一区| 中文字幕中文字幕 亚洲国产| 欧美日韩熟女一区二区三区| 很黄很污很色的午夜网站在线观看 | 亚洲人妻av毛片在线| 日日爽天天干夜夜操| 一个色综合男人天堂| 在线免费观看国产精品黄色| 亚洲最大黄了色网站| 丝袜长腿第一页在线| 我想看操逼黄色大片| 国产老熟女伦老熟妇ⅹ| 在线观看的a站 最新| 中文字幕 人妻精品| 国产又大又黄免费观看| 硬鸡巴动态操女人逼视频| 午夜在线观看一区视频| 婷婷六月天中文字幕| 天天日天天爽天天干| 在线免费观看亚洲精品电影| 日本脱亚入欧是指什么| 欧美日韩精品永久免费网址| 一区二区三区综合视频| 小穴多水久久精品免费看| 福利视频网久久91| 欧美专区日韩专区国产专区| 哥哥姐姐综合激情小说| 天天日天天操天天摸天天舔| 亚洲精品午夜aaa久久| 精品亚洲中文字幕av| 大鸡巴后入爆操大屁股美女| 午夜久久香蕉电影网| 日韩成人综艺在线播放| 国产又粗又猛又爽又黄的视频在线| 少妇人妻二三区视频| 美女视频福利免费看| 99久久99久国产黄毛片| 中文字幕AV在线免费看 | 亚洲精品久久视频婷婷| 亚洲精品av在线观看| 九九热99视频在线观看97| 午夜精品福利一区二区三区p| 亚洲欧美综合在线探花| 日本成人不卡一区二区| 精品人妻每日一部精品| 熟女视频一区,二区,三区| av中文在线天堂精品| 天天躁夜夜躁日日躁a麻豆| 我想看操逼黄色大片| 亚洲天堂av最新网址| 亚洲成人av一区在线| 男人操女人的逼免费视频| 国产一区二区神马久久| av在线免费中文字幕| 亚洲免费在线视频网站| 日韩在线视频观看有码在线| 成人30分钟免费视频| 在线观看国产免费麻豆| 国产大学生援交正在播放| 欧美成人综合色在线噜噜| 在线制服丝袜中文字幕| 亚洲福利精品视频在线免费观看| 亚洲中文字幕综合小综合| 在线免费观看日本伦理| 2012中文字幕在线高清| 大香蕉大香蕉在线有码 av| 久久精品36亚洲精品束缚| 超碰在线观看免费在线观看| 亚洲精品 欧美日韩| 国产日本精品久久久久久久| 国产熟妇一区二区三区av| 亚洲女人的天堂av| 一区二区三区国产精选在线播放| 国产黄色大片在线免费播放| 大香蕉大香蕉在线看| 2020韩国午夜女主播在线| 插小穴高清无码中文字幕| 国产欧美精品一区二区高清| 亚洲成人av在线一区二区| 亚洲欧美一区二区三区爱爱动图 | 动漫精品视频在线观看| 国产精品国产三级麻豆| 中国熟女一区二区性xx| caoporn蜜桃视频| 人人妻人人爽人人添夜| 插小穴高清无码中文字幕| 端庄人妻堕落挣扎沉沦| 国产丰满熟女成人视频| 亚洲欧洲av天堂综合| 国产日本欧美亚洲精品视| 男生舔女生逼逼视频| 孕妇奶水仑乱A级毛片免费看| 在线不卡成人黄色精品| 欧美老鸡巴日小嫩逼| 国产精品视频资源在线播放| 亚洲国产欧美国产综合在线| 日本韩国亚洲综合日韩欧美国产| 五月色婷婷综合开心网4438| 欧美国品一二三产区区别| 97成人免费在线观看网站| 日美女屁股黄邑视频| 亚洲天堂有码中文字幕视频 | 国产内射中出在线观看| 青青青青青免费视频| 老司机免费福利视频网| 亚洲国产香蕉视频在线播放| 国产使劲操在线播放| 丝袜肉丝一区二区三区四区在线| 青青草国内在线视频精选| 亚洲精品高清自拍av| 国际av大片在线免费观看| 97瑟瑟超碰在线香蕉| av久久精品北条麻妃av观看| 中文字幕日韩精品日本| h国产小视频福利在线观看| 欧美日韩情色在线观看| 日韩黄色片在线观看网站| 国产精品久久久久久久精品视频| 91片黄在线观看喷潮| 国产极品精品免费视频| 亚洲一区二区久久久人妻| 欧美80老妇人性视频| 男生用鸡操女生视频动漫| 女人精品内射国产99| 亚洲国产美女一区二区三区软件| gav成人免费播放| 一区二区三区综合视频| 蜜桃臀av蜜桃臀av| 亚洲福利精品视频在线免费观看| 黄色av网站免费在线| 日本av高清免费网站| 成人免费公开视频无毒| 国产视频一区二区午夜| 自拍偷拍vs一区二区三区| 日视频免费在线观看| 天天干天天插天天谢| aaa久久久久久久久| 欧美精品免费aaaaaa| 大鸡吧插逼逼视频免费看 | 欧美成人综合视频一区二区 | 老熟妇凹凸淫老妇女av在线观看| 91大屁股国产一区二区| 小穴多水久久精品免费看| 国产普通话插插视频| 99婷婷在线观看视频| 亚洲av日韩高清hd| 一区二区免费高清黄色视频| 国产福利小视频大全| 亚洲少妇人妻无码精品| 美女被肏内射视频网站| 天天躁夜夜躁日日躁a麻豆| aiss午夜免费视频| 午夜在线观看岛国av,com| 久久丁香花五月天色婷婷| 成年人午夜黄片视频资源| 伊人情人综合成人久久网小说 | av俺也去在线播放| 日视频免费在线观看| 国产av一区2区3区| 欧美精品亚洲精品日韩在线| 最新日韩av传媒在线| 国产久久久精品毛片| 中文字幕第一页国产在线| 日韩特级黄片高清在线看| 日本少妇人妻xxxxx18| 亚洲成人国产综合一区| 国产在线观看黄色视频| 欧美亚洲自偷自拍 在线| av成人在线观看一区| 人妻无码色噜噜狠狠狠狠色| 中文字幕日韩精品日本| 中文字幕在线欧美精品| 国产一区二区三免费视频| 午夜在线精品偷拍一区二 | 欧美激情精品在线观看| 久久久久五月天丁香社区| 韩国AV无码不卡在线播放| 性感美女高潮视频久久久| 成人亚洲精品国产精品| 丰满的继坶3中文在线观看| 亚洲 图片 欧美 图片| 麻豆精品成人免费视频| 人妻熟女在线一区二区| 日美女屁股黄邑视频| 国产九色91在线视频| 久久精品国产亚洲精品166m| 偷拍自拍国产在线视频| 青娱乐最新视频在线| 丝袜长腿第一页在线| 亚洲欧美人精品高清| 日韩精品激情在线观看| 美味人妻2在线播放| 97人妻人人澡爽人人精品| 大香蕉伊人中文字幕| 老有所依在线观看完整版| 抽查舔水白紧大视频| 青青青视频自偷自拍38碰| 夜色17s精品人妻熟女| 亚洲另类在线免费观看| 人人超碰国字幕观看97| 老师啊太大了啊啊啊尻视频| 久久久久久久久久一区二区三区 | 国产精品系列在线观看一区二区| 91超碰青青中文字幕| 岳太深了紧紧的中文字幕| 亚洲综合图片20p| 人妻少妇性色欲欧美日韩| 国产精选一区在线播放| 3344免费偷拍视频| 青青青国产片免费观看视频| 中文字幕av男人天堂| AV无码一区二区三区不卡| 国产伦精品一区二区三区竹菊| 国内资源最丰富的网站| 亚洲国产欧美国产综合在线| 中文字幕高清免费在线人妻| japanese日本熟妇另类| 91精品国产综合久久久蜜| 国产福利小视频大全| 人妻久久无码中文成人| 精品亚洲国产中文自在线| 老熟妇xxxhd老熟女| 国产精品视频欧美一区二区| 福利在线视频网址导航| 色综合天天综合网国产成人| 久久99久久99精品影院| 国产精品久久久久久久女人18| 国产亚洲四十路五十路| 国产一区二区久久久裸臀| 在线播放国产黄色av| 天天摸天天亲天天舔天天操天天爽 | 天天日天天日天天射天天干 | 精品av久久久久久久| 国产91嫩草久久成人在线视频| 日韩影片一区二区三区不卡免费| 亚洲av日韩精品久久久| 天天射夜夜操狠狠干| 在线观看日韩激情视频| 亚洲无码一区在线影院| 99久久超碰人妻国产| 青青青青视频在线播放| 80电影天堂网官网| 十八禁在线观看地址免费| 美女大bxxxx内射| 阴茎插到阴道里面的视频| 欧美 亚洲 另类综合| 青青草视频手机免费在线观看| 91精品国产高清自在线看香蕉网| 国产亚州色婷婷久久99精品| 欧美特色aaa大片| 久久国产精品精品美女| 人妻自拍视频中国大陆| 黑人乱偷人妻中文字幕| 国产精品人妻熟女毛片av久| 亚洲精品麻豆免费在线观看| 1区2区3区4区视频在线观看| 美女张开腿让男生操在线看| 人妻丝袜精品中文字幕| 国产精品成久久久久三级蜜臀av| 人妻久久无码中文成人| 亚洲精品国品乱码久久久久 | 97精品成人一区二区三区| 亚洲蜜臀av一区二区三区九色| 青青草国内在线视频精选| 天天日天天干天天舔天天射| 老师让我插进去69AV| 午夜蜜桃一区二区三区| 亚洲 人妻 激情 中文| 国产亚洲欧美另类在线观看| 日日爽天天干夜夜操| 国产实拍勾搭女技师av在线| 国产福利小视频免费观看| 中文乱理伦片在线观看| 91久久综合男人天堂| 免费高清自慰一区二区三区网站 | 99热久久极品热亚洲| av老司机精品在线观看| 亚洲精品国产在线电影| 天天干天天爱天天色| 任你操任你干精品在线视频| 成人久久精品一区二区三区| 日韩视频一区二区免费观看| 人妻少妇精品久久久久久| 精品乱子伦一区二区三区免费播| 蜜桃视频在线欧美一区| 啊啊好大好爽啊啊操我啊啊视频| caoporn蜜桃视频| 成人亚洲精品国产精品| 福利午夜视频在线观看| 蜜桃色婷婷久久久福利在线| 99热这里只有精品中文| 欧洲日韩亚洲一区二区三区| 久久这里有免费精品| 成人蜜臀午夜久久一区| 亚洲熟色妇av日韩熟色妇在线| 亚洲一区二区三区五区| 青青草人人妻人人妻| 久久久久久久精品老熟妇| 男人的网址你懂的亚洲欧洲av| 蜜臀av久久久久蜜臀av麻豆| 美女骚逼日出水来了| 欧美精产国品一二三产品价格| 硬鸡巴动态操女人逼视频| 欧美80老妇人性视频| 天天日天天干天天搡| 黄色男人的天堂视频| 手机看片福利盒子日韩在线播放| 女蜜桃臀紧身瑜伽裤| 成人国产小视频在线观看| 97成人免费在线观看网站| 岛国av高清在线成人在线| 亚洲天堂有码中文字幕视频| 男人的天堂在线黄色| 天天想要天天操天天干| 亚洲av在线观看尤物| 蜜桃臀av蜜桃臀av| 最新的中文字幕 亚洲| 91国偷自产一区二区三区精品| 黄网十四区丁香社区激情五月天| 黄色中文字幕在线播放| 福利片区一区二体验区| 精品人妻一二三区久久| 亚洲国产免费av一区二区三区| AV无码一区二区三区不卡| okirakuhuhu在线观看| 2022国产精品视频| 偷拍自拍福利视频在线观看| 51国产偷自视频在线播放| 国产午夜无码福利在线看| 日韩美女精品视频在线观看网站 | gay gay男男瑟瑟在线网站| 免费国产性生活视频| 日韩在线中文字幕色| 老司机福利精品免费视频一区二区| 天天操,天天干,天天射| 2022国产综合在线干| 日韩欧美中文国产在线 | 午夜精品九一唐人麻豆嫩草成人| 欧美亚洲国产成人免费在线 | 久久美欧人妻少妇一区二区三区 | 成人动漫大肉棒插进去视频| 激情国产小视频在线| 伊人日日日草夜夜草| 亚洲午夜电影在线观看| 大屁股肉感人妻中文字幕在线| 2019av在线视频| 国产伊人免费在线播放| gay gay男男瑟瑟在线网站| 不卡一区一区三区在线| 大香蕉大香蕉大香蕉大香蕉大香蕉| 91九色porny蝌蚪国产成人| 国产精品亚洲а∨天堂免| 免费无毒热热热热热热久| 国产男女视频在线播放| 国产成人自拍视频播放| 欧洲国产成人精品91铁牛tv| 不戴胸罩引我诱的隔壁的人妻| 一区二区久久成人网| 第一福利视频在线观看| 黄工厂精品视频在线观看| 麻豆精品成人免费视频| 人人妻人人爽人人添夜| 黄色视频在线观看高清无码| 视频一区二区三区高清在线| 成人伊人精品色xxxx视频| 青青草亚洲国产精品视频| 日本午夜久久女同精女女| 国产亚洲欧美视频网站| 馒头大胆亚洲一区二区| 丰满熟女午夜福利视频| 青青操免费日综合视频观看| 少妇深喉口爆吞精韩国| 欧美 亚洲 另类综合| 亚洲美女高潮喷浆视频| 亚洲精品国品乱码久久久久| 五十路息与子猛烈交尾视频| 国产欧美日韩第三页| 夜色撩人久久7777| 日本特级片中文字幕| 大白屁股精品视频国产| 热思思国产99re| 激情伦理欧美日韩中文字幕| 大鸡吧插逼逼视频免费看| 欧美麻豆av在线播放| 插逼视频双插洞国产操逼插洞 | 天天日天天日天天射天天干 | 一区二区免费高清黄色视频| 日本乱人一区二区三区| 久草视频 久草视频2| 欧美美女人体视频一区| 91久久国产成人免费网站| 2025年人妻中文字幕乱码在线| 免费成人av中文字幕| mm131美女午夜爽爽爽| brazzers欧熟精品系列| 啊慢点鸡巴太大了啊舒服视频| 91天堂天天日天天操| av线天堂在线观看| 天天干天天操天天扣| 日本少妇人妻xxxxx18| 天天日天天干天天搡| 久久久极品久久蜜桃| 亚国产成人精品久久久| 午夜在线精品偷拍一区二| 国产精品一区二区久久久av| 搞黄色在线免费观看| 99精品一区二区三区的区| 人妻3p真实偷拍一二区| 天天干狠狠干天天操| 欧美交性又色又爽又黄麻豆| 日韩av熟妇在线观看| 国产之丝袜脚在线一区二区三区| 特一级特级黄色网片| 国产美女精品福利在线| 成人国产影院在线观看| 亚洲欧美综合另类13p| 性色蜜臀av一区二区三区| 国产av一区2区3区| 精彩视频99免费在线| 一级A一级a爰片免费免会员| 99一区二区在线观看| 久久久久91精品推荐99| 日日摸夜夜添夜夜添毛片性色av| 国产一区自拍黄视频免费观看| 亚洲成人三级在线播放| 人妻另类专区欧美制服| 97a片免费在线观看| 亚洲va欧美va人人爽3p| 女蜜桃臀紧身瑜伽裤| 九色视频在线观看免费| 五月婷婷在线观看视频免费| 欧美女同性恋免费a| 丝袜肉丝一区二区三区四区在线| 国产aⅴ一线在线观看| 激情小视频国产在线| 欧美精品 日韩国产| 欧美成人综合色在线噜噜| 成人影片高清在线观看| 黄色在线观看免费观看在线| 欧美熟妇一区二区三区仙踪林| 91久久精品色伊人6882| 久久久久国产成人精品亚洲午夜| 伊人开心婷婷国产av| 人妻丝袜精品中文字幕| 久久久人妻一区二区| 看一级特黄a大片日本片黑人| 色天天天天射天天舔| 国产精品福利小视频a| 成人sm视频在线观看| 日本黄在免费看视频| 五十路丰满人妻熟妇| 午夜大尺度无码福利视频| 欧美日韩人妻久久精品高清国产 | 欧美亚洲国产成人免费在线| 绝色少妇高潮3在线观看| 91免费观看在线网站| 中文亚洲欧美日韩无线码| 天天射夜夜操狠狠干| 99精品视频之69精品视频| 在线观看操大逼视频| 中文字幕在线视频一区二区三区| 国产精品中文av在线播放| 欧美色呦呦最新网址| 91精品国产观看免费| 19一区二区三区在线播放| 激情国产小视频在线| 日韩人妻xxxxx| 99久久99一区二区三区| 免费高清自慰一区二区三区网站| 亚洲卡1卡2卡三卡四老狼| 91在线免费观看成人| 操日韩美女视频在线免费看| 成年美女黄网站18禁久久| 天天操天天爽天天干| 国产亚洲精品视频合集| 黑人乱偷人妻中文字幕| 超pen在线观看视频公开97| 天天射夜夜操综合网| 91久久国产成人免费网站| 亚洲 清纯 国产com| 亚洲熟女女同志女同| 亚洲国产第一页在线观看| 青青青国产片免费观看视频| 操日韩美女视频在线免费看| 青青青aaaa免费| 91大屁股国产一区二区| 干逼又爽又黄又免费的视频| 91 亚洲视频在线观看| 免费手机黄页网址大全| 中文字幕,亚洲人妻| 五色婷婷综合狠狠爱| 人妻丝袜av在线播放网址| 狠狠的往里顶撞h百合| 天天想要天天操天天干| 色婷婷久久久久swag精品| 黄色片一级美女黄色片| 亚洲av无乱一区二区三区性色| 日本高清撒尿pissing| 国产高清精品一区二区三区| 亚洲视频在线观看高清| 国产日韩欧美美利坚蜜臀懂色| 91中文字幕免费在线观看| 大白屁股精品视频国产| 岛国免费大片在线观看| 久久久久久国产精品| 亚洲人人妻一区二区三区| 成年人免费看在线视频| 欧美一区二区中文字幕电影| 婷婷久久一区二区字幕网址你懂得| 美女视频福利免费看| 欧美男同性恋69视频| 一色桃子久久精品亚洲| 天天做天天干天天操天天射| 亚洲免费va在线播放| 55夜色66夜色国产精品站| 免费在线黄色观看网站| 欧美viboss性丰满| 日本高清撒尿pissing| 天天日天天干天天要| 国产大鸡巴大鸡巴操小骚逼小骚逼 | 午夜毛片不卡在线看| 天天干天天插天天谢| 欧美一区二区三区在线资源 | 久久精品美女免费视频| 亚洲天堂成人在线观看视频网站| 韩国爱爱视频中文字幕| 日本特级片中文字幕| 天天操天天爽天天干| 不卡一不卡二不卡三| 最新中文字幕乱码在线| 精品一区二区三区午夜| av网址在线播放大全| 中文字幕免费在线免费| av欧美网站在线观看| 青青青aaaa免费| 国产一区av澳门在线观看| 国产精品黄色的av| 日本免费视频午夜福利视频| 99国内小视频在现欢看| 九色精品视频在线播放| 亚洲欧美日韩视频免费观看| 粉嫩av蜜乳av蜜臀| 夏目彩春在线中文字幕| 一区二区三区av高清免费| 日韩精品电影亚洲一区| 超碰97免费人妻麻豆| 亚洲 中文 自拍 另类 欧美| 91综合久久亚洲综合| 国产精品入口麻豆啊啊啊| 亚洲精品三级av在线免费观看| 国产精品亚洲а∨天堂免| 中文字幕在线观看极品视频| 精品欧美一区二区vr在线观看| 成人av电影免费版| 自拍偷拍 国产资源| 国产一区二区久久久裸臀| 国产日韩精品电影7777| 久久一区二区三区人妻欧美| 日韩欧美一级aa大片| 日本精品一区二区三区在线视频。 | 久久久久久久精品成人热| 国产视频网站一区二区三区 | 精品一区二区三区在线观看| 香蕉片在线观看av| 激情五月婷婷综合色啪| 福利视频广场一区二区| 婷婷久久久综合中文字幕| xxx日本hd高清| 欧美久久一区二区伊人| 中文字幕一区二区自拍| 大香蕉日本伊人中文在线| 欧美区一区二区三视频| 成年美女黄网站18禁久久| 亚洲成人av一区在线| 极品性荡少妇一区二区色欲| 成人18禁网站在线播放| 性感美女福利视频网站| 亚洲成人熟妇一区二区三区| 亚洲 中文字幕在线 日韩| 天堂v男人视频在线观看| 国产黄色大片在线免费播放| 亚洲av极品精品在线观看| 性欧美日本大妈母与子| 精品老妇女久久9g国产| 欧美视频一区免费在线| 男人的网址你懂的亚洲欧洲av| 国产精品成人xxxx| 中文字幕 码 在线视频| 欧美偷拍自拍色图片| 欧美一区二区中文字幕电影 | 日韩北条麻妃一区在线| 天天干天天爱天天色| 2021最新热播中文字幕| 国产精品亚洲а∨天堂免| 亚洲欧美日韩视频免费观看| 香蕉aⅴ一区二区三区| 国产精品人久久久久久| 国产又粗又猛又爽又黄的视频美国| 人妻另类专区欧美制服| 在线观看日韩激情视频| 亚洲自拍偷拍综合色| 欧美aa一级一区三区四区| 精品亚洲在线免费观看| 天天日夜夜操天天摸| 亚洲变态另类色图天堂网| 天堂av狠狠操蜜桃| 中文字幕一区二区三区蜜月| 亚洲视频在线观看高清| 57pao国产一区二区| 亚洲黄色av网站免费播放| av老司机亚洲一区二区| 日韩av大胆在线观看| aiss午夜免费视频| 国产精品精品精品999| 人人妻人人爱人人草| 亚洲综合在线视频可播放| 亚洲青青操骚货在线视频| 日韩欧美在线观看不卡一区二区 | 男人的网址你懂的亚洲欧洲av| 2022国产综合在线干| 国产精品黄页网站视频| 天天操天天射天天操天天天| 色婷婷久久久久swag精品| 3337p日本欧洲大胆色噜噜| 白嫩白嫩美女极品国产在线观看| 92福利视频午夜1000看 | 日本一二三中文字幕| 巨乳人妻日下部加奈被邻居中出| 黄色无码鸡吧操逼视频| 夫妻在线观看视频91| 97成人免费在线观看网站| 国产亚洲欧美45p| 北条麻妃高跟丝袜啪啪| 91桃色成人网络在线观看| 精品亚洲在线免费观看| 精品久久久久久久久久久久人妻| 成人av天堂丝袜在线观看| 亚洲美女美妇久久字幕组| 久草视频中文字幕在线观看| 亚洲 中文字幕在线 日韩| 大胸性感美女羞爽操逼毛片| 熟女人妻在线观看视频| 91 亚洲视频在线观看| 精品老妇女久久9g国产| 天天干天天操天天玩天天射 | 亚洲午夜高清在线观看| 国产又粗又猛又爽又黄的视频在线| sspd152中文字幕在线| 国产女人被做到高潮免费视频| 国产一级麻豆精品免费| 超级av免费观看一区二区三区| 久久久极品久久蜜桃| 91久久精品色伊人6882| 黄色三级网站免费下载| 免费黄高清无码国产| 日本午夜久久女同精女女| 国产成人精品一区在线观看 | 天干天天天色天天日天天射| 成人国产激情自拍三区| 日韩美女精品视频在线观看网站| 97精品视频在线观看| 中文字幕在线视频一区二区三区 | 亚洲精品成人网久久久久久小说| 小穴多水久久精品免费看| 97人妻夜夜爽二区欧美极品| 亚洲成人情色电影在线观看| 国产亚洲天堂天天一区| 91免费观看在线网站| 美女大bxxxx内射| 亚洲麻豆一区二区三区| 天天日天天做天天日天天做| 久久久久久9999久久久久| 少妇露脸深喉口爆吞精| 精品久久久久久久久久久99| 亚洲av琪琪男人的天堂| 国产av福利网址大全| 1区2区3区不卡视频| 久久久久久久精品老熟妇| 国产一级精品综合av| 国产精品国产三级国产午| 熟妇一区二区三区高清版| 偷拍自拍视频图片免费| 欧美成人猛片aaaaaaa| av久久精品北条麻妃av观看| 成年人黄视频在线观看| free性日本少妇| 亚洲 欧美 精品 激情 偷拍 | 自拍偷拍亚洲欧美在线视频| 亚洲国产欧美一区二区丝袜黑人| 韩国AV无码不卡在线播放| 人人人妻人人澡人人| 一级黄色片夫妻性生活| 中文字幕第一页国产在线| 国产精品熟女久久久久浪潮| 三上悠亚和黑人665番号| 亚洲av无码成人精品区辽| 97精品综合久久在线| 在线观看av2025| 国产精品黄页网站视频| 日噜噜噜夜夜噜噜噜天天噜噜噜| 99国产精品窥熟女精品| 啊慢点鸡巴太大了啊舒服视频| 青青青青操在线观看免费| 精品一区二区三区欧美| 欧美亚洲自偷自拍 在线| 自拍 日韩 欧美激情| 日本熟妇喷水xxx| 国产黄网站在线观看播放| 在线观看亚洲人成免费网址| 桃色视频在线观看一区二区| 国产综合精品久久久久蜜臀| 91九色porny国产蝌蚪视频| 免费在线播放a级片| 姐姐的朋友2在线观看中文字幕| 大鸡巴操娇小玲珑的女孩逼| japanese五十路熟女熟妇| av在线免费中文字幕| 欧美成人黄片一区二区三区 | 在线观看欧美黄片一区二区三区| 激情啪啪啪啪一区二区三区| 国产高清在线观看1区2区| 午夜激情久久不卡一区二区| 337p日本大胆欧美人| 日本av熟女在线视频| 中出中文字幕在线观看 | 任你操视频免费在线观看| 午夜激情高清在线观看| 亚洲欧美成人综合视频| 美女 午夜 在线视频| 狠狠躁夜夜躁人人爽天天天天97| 东京热男人的av天堂| 国产精品国产精品一区二区| 成年人黄视频在线观看| 亚洲av第国产精品| 日本丰满熟妇大屁股久久| 婷婷色国产黑丝少妇勾搭AV| 免费岛国喷水视频在线观看 | 国产午夜男女爽爽爽爽爽视频 | 亚洲精品久久视频婷婷| 真实国产乱子伦一区二区| 国产精品精品精品999| 天天操,天天干,天天射| 国产美女一区在线观看| 2021最新热播中文字幕| 国内精品在线播放第一页| 红杏久久av人妻一区| 久久人人做人人妻人人玩精品vr| 3337p日本欧洲大胆色噜噜| 亚欧在线视频你懂的| 天天摸天天干天天操科普| 日比视频老公慢点好舒服啊| 91国产在线免费播放| 欧美视频不卡一区四区| rct470中文字幕在线| 久久久超爽一二三av| 中文字幕人妻三级在线观看| 天天插天天狠天天操| 中文字幕视频一区二区在线观看 | 黄色片一级美女黄色片| 香蕉片在线观看av| 欧美综合婷婷欧美综合| 日韩美女搞黄视频免费| 亚洲成人免费看电影| 一区二区三区综合视频| 成人sm视频在线观看| 亚洲免费va在线播放| 天天操夜夜骑日日摸| 天天日天天鲁天天操| 中文字幕av第1页中文字幕| 男人靠女人的逼视频| 2020中文字幕在线播放| 青青色国产视频在线| 国产精品国产三级国产精东 | 久久久极品久久蜜桃| 亚洲一区制服丝袜美腿| 人人妻人人澡欧美91精品| 亚洲国产精品免费在线观看| 中文字幕人妻一区二区视频| 青青青青草手机在线视频免费看| 亚洲在线观看中文字幕av| 粉嫩av懂色av蜜臀av| 国产精品伦理片一区二区| 欧美成人精品在线观看| 国产91久久精品一区二区字幕| 亚洲高清国产一区二区三区| 社区自拍揄拍尻屁你懂的| 天天摸天天干天天操科普| 日韩激情文学在线视频 | av黄色成人在线观看| 一级a看免费观看网站| 国产精品精品精品999| 天天日天天干天天搡| 国产精品黄大片在线播放| 免费黄色成人午夜在线网站| 超污视频在线观看污污污| 免费费一级特黄真人片| 9久在线视频只有精品| 女警官打开双腿沦为性奴| 青青草人人妻人人妻| 日本美女性生活一级片| 91精品国产91青青碰| 绝色少妇高潮3在线观看| 天天干天天操天天玩天天射| av网址国产在线观看| 欧美一级色视频美日韩| 欧美成人小视频在线免费看| 超级福利视频在线观看| 国产精品国色综合久久| 亚洲中文精品人人免费| 国产精品自拍在线视频| 精品国产乱码一区二区三区乱| 熟女少妇激情五十路| 国产福利小视频二区| 一区二区麻豆传媒黄片| 美女福利写真在线观看视频| 欧美国品一二三产区区别| av日韩在线观看大全| 亚洲av天堂在线播放| 亚洲午夜电影在线观看| 亚洲最大免费在线观看| 99精品久久久久久久91蜜桃| 亚洲 欧美 精品 激情 偷拍| 丝袜亚洲另类欧美变态| 久久h视频在线观看| 男生舔女生逼逼视频| 欧美成人黄片一区二区三区| 99一区二区在线观看| 78色精品一区二区三区| 无码中文字幕波多野不卡| a v欧美一区=区三区| 播放日本一区二区三区电影| 青青青青青青草国产| 黄色片年轻人在线观看| 播放日本一区二区三区电影| 欧美久久久久久三级网| 无码中文字幕波多野不卡| 蜜桃久久久久久久人妻| 在线免费观看靠比视频的网站| 久草福利电影在线观看| 国产精品日韩欧美一区二区| gav成人免费播放| 亚洲av无硬久久精品蜜桃| 69精品视频一区二区在线观看| 青春草视频在线免费播放| 国产九色91在线视频| 亚洲精品久久视频婷婷| nagger可以指黑人吗| 大香蕉伊人中文字幕| 9l人妻人人爽人人爽| 天码人妻一区二区三区在线看| 亚洲福利精品福利精品福利| 黑人借宿ntr人妻的沦陷2| 日本黄在免费看视频| 日本人妻欲求不满中文字幕| 天天射夜夜操综合网| 亚洲天天干 夜夜操| 亚洲一区二区三区精品视频在线| 老司机在线精品福利视频| 国产伦精品一区二区三区竹菊| 午夜美女福利小视频| 欧美亚洲偷拍自拍色图| 在线新三级黄伊人网| 欧美精品 日韩国产| 蜜桃视频入口久久久| 亚洲专区激情在线观看视频| 女生被男生插的视频网站| 天码人妻一区二区三区在线看| 亚洲天堂精品福利成人av| 福利视频一区二区三区筱慧| 欧美精品免费aaaaaa| 国产高清女主播在线| 午夜av一区二区三区| a v欧美一区=区三区| 日韩黄色片在线观看网站| aⅴ五十路av熟女中出| 亚洲午夜在线视频福利| 狠狠鲁狠狠操天天晚上干干| 青青青aaaa免费| 日本高清撒尿pissing| 亚洲欧美国产综合777| 国产午夜男女爽爽爽爽爽视频| 一二三区在线观看视频| 无码国产精品一区二区高潮久久4| 黄色黄色黄片78在线| 成人激情文学网人妻| 91啪国自产中文字幕在线| 亚洲在线免费h观看网站| 适合午夜一个人看的视频| 国产精品自偷自拍啪啪啪| 久久热这里这里只有精品| 在线免费观看日本片| 一区国内二区日韩三区欧美| 亚洲午夜电影之麻豆| 密臀av一区在线观看| 日韩欧美制服诱惑一区在线| 久久久精品国产亚洲AV一| 大白屁股精品视频国产| 最新国产亚洲精品中文在线| 精品久久婷婷免费视频| 美女张开两腿让男人桶av| 2021久久免费视频| www,久久久,com| av新中文天堂在线网址| 国产乱子伦一二三区| 亚洲视频乱码在线观看| 欧美香蕉人妻精品一区二区| 男女啪啪视频免费在线观看| 精品av国产一区二区三区四区| 欧美日韩激情啪啪啪| 天天日天天玩天天摸| 国产欧美日韩第三页| 水蜜桃一区二区三区在线观看视频| 欧美 亚洲 另类综合| 日韩视频一区二区免费观看| 美女张开腿让男生操在线看| 欧美地区一二三专区| 大香蕉大香蕉大香蕉大香蕉大香蕉| av在线免费中文字幕| 日韩伦理短片在线观看| 最新国产精品网址在线观看| 在线观看911精品国产| 久久久久久久亚洲午夜综合福利| 中文字幕一区的人妻欧美日韩| 国产黄色高清资源在线免费观看| 久久尻中国美女视频| 亚洲国产成人在线一区| 哥哥姐姐综合激情小说| 免费啪啪啪在线观看视频| 伊人网中文字幕在线视频| 日韩美女精品视频在线观看网站| 91国语爽死我了不卡| 水蜜桃一区二区三区在线观看视频| 91国内精品久久久久精品一| 毛片av在线免费看| 人妻无码色噜噜狠狠狠狠色| 亚洲偷自拍高清视频| 激情人妻校园春色亚洲欧美 | 激情人妻校园春色亚洲欧美| 97年大学生大白天操逼| 白白操白白色在线免费视频| 三级等保密码要求条款| 适合午夜一个人看的视频| 人人爱人人妻人人澡39| 伊人综合免费在线视频| 91免费观看在线网站| 亚洲精品亚洲人成在线导航| 水蜜桃一区二区三区在线观看视频| 80电影天堂网官网| 国产91嫩草久久成人在线视频| 色综合天天综合网国产成人| 欧亚乱色一区二区三区| 女生自摸在线观看一区二区三区| 成年人黄色片免费网站| 天天想要天天操天天干| av中文字幕福利网| 亚洲少妇人妻无码精品| 国产亚洲精品视频合集| 日韩欧美高清免费在线| 天天日天天透天天操| 日韩一区二区电国产精品| 肏插流水妹子在线乐播下载| 在线免费观看国产精品黄色| 大鸡巴插入美女黑黑的阴毛| 国语对白xxxx乱大交| 天天日天天添天天爽| 欧美怡红院视频在线观看| 四川五十路熟女av| 国产精品精品精品999| 国产日韩av一区二区在线| 成年人该看的视频黄免费| 久久h视频在线观看| 这里只有精品双飞在线播放| 在线观看视频 你懂的| 亚洲精品亚洲人成在线导航| 9国产精品久久久久老师| 国产午夜无码福利在线看| 中文字幕免费福利视频6| 精品久久婷婷免费视频| 农村胖女人操逼视频| 性感美女高潮视频久久久| 国产乱子伦一二三区| 欧美中文字幕一区最新网址| 久久精品久久精品亚洲人| 天天日天天爽天天爽| 亚洲伊人久久精品影院一美女洗澡 | 久久丁香花五月天色婷婷| 欧美视频中文一区二区三区| 亚洲自拍偷拍综合色| 91在线免费观看成人| 久久精品国产999| 色综合久久久久久久久中文| 日本一道二三区视频久久| 亚洲一区二区三区久久午夜| 欧美国产亚洲中英文字幕| 久久一区二区三区人妻欧美| 色呦呦视频在线观看视频| 国产女人被做到高潮免费视频| 18禁网站一区二区三区四区| 国产性感美女福利视频| 青青青视频手机在线观看| 激情内射在线免费观看| 亚洲 国产 成人 在线| 黄色成人在线中文字幕| 日韩精品中文字幕福利| 国产欧美日韩在线观看不卡| 免费岛国喷水视频在线观看| 最近中文2019年在线看| 成年人的在线免费视频| 中文字幕av熟女人妻| 一本一本久久a久久精品综合不卡| 偷拍自拍福利视频在线观看| 4个黑人操素人视频网站精品91| 中文字幕日韩无敌亚洲精品| www骚国产精品视频| 日日操夜夜撸天天干| 午夜精品久久久久久99热| 在线观看一区二区三级| 国产视频网站一区二区三区 | 国产性感美女福利视频| 天天操,天天干,天天射| 日韩av熟妇在线观看| 久久久麻豆精亚洲av麻花| 成人在线欧美日韩国产| 亚洲一区二区三区uij| 黑人解禁人妻叶爱071| 欧美精品 日韩国产| 天天日天天透天天操| 女生被男生插的视频网站| 精品美女福利在线观看| 女同互舔一区二区三区| 九色视频在线观看免费| 免费看美女脱光衣服的视频| 亚洲成av人无码不卡影片一| 韩国一级特黄大片做受| 青青色国产视频在线| 搡老妇人老女人老熟女| 99热99这里精品6国产| 亚洲精品国产久久久久久| 亚洲国产免费av一区二区三区 | 91社福利《在线观看| 91成人在线观看免费视频| 日本xx片在线观看| 亚洲一级美女啪啪啪| 伊人成人综合开心网| 亚洲一区av中文字幕在线观看| 日韩熟女av天堂系列| 97精品综合久久在线| 伊人开心婷婷国产av| 日本一区美女福利视频| 国产乱子伦一二三区| 一区二区三区的久久的蜜桃的视频| 偷拍3456eee| 99热色原网这里只有精品| 青青草成人福利电影| 亚洲av日韩av第一区二区三区| 色综合久久无码中文字幕波多| 人妻少妇精品久久久久久| 91久久国产成人免费网站| 亚洲日本一区二区三区| 一区二区三区蜜臀在线| 夜夜骑夜夜操夜夜奸| 亚洲午夜伦理视频在线| 欧美中文字幕一区最新网址| 成人蜜臀午夜久久一区| 国产精品久久久久国产三级试频| 97超碰最新免费在线观看| 亚洲在线一区二区欧美| 国产熟妇人妻ⅹxxxx麻豆| 男人的天堂av日韩亚洲| 午夜在线一区二区免费| 黑人借宿ntr人妻的沦陷2| 亚洲国产美女一区二区三区软件| 一二三区在线观看视频| 亚洲午夜伦理视频在线| gay gay男男瑟瑟在线网站| 91精品国产麻豆国产| 婷婷综合亚洲爱久久| 精品首页在线观看视频| 精内国产乱码久久久久久 | 91色网站免费在线观看| 亚洲欧美清纯唯美另类| 性感美女高潮视频久久久| 亚洲特黄aaaa片| 国产自拍在线观看成人| 精品欧美一区二区vr在线观看 | 91精品国产91青青碰| 93人妻人人揉人人澡人人| 亚洲精品欧美日韩在线播放 | 免费看国产又粗又猛又爽又黄视频| 黄工厂精品视频在线观看| 亚洲中文精品字幕在线观看| 国产chinesehd精品麻豆| 99re6热在线精品| 美日韩在线视频免费看| 免费在线观看污污视频网站| 亚洲精品一区二区三区老狼| 亚洲丝袜老师诱惑在线观看| 亚洲美女美妇久久字幕组| 成人午夜电影在线观看 久久| 非洲黑人一级特黄片| 亚洲成人午夜电影在线观看 | 超碰97免费人妻麻豆| 国产福利在线视频一区| 亚洲av无硬久久精品蜜桃| 日本人妻少妇18—xx| 在线播放一区二区三区Av无码| 二区中出在线观看老师| 成人免费公开视频无毒| 欧美在线偷拍视频免费看| 成年人黄视频在线观看| 久久久久久性虐视频| 欧美日韩亚洲国产无线码| 唐人色亚洲av嫩草| 国产露脸对白在线观看| 天天日夜夜干天天操| 最近中文字幕国产在线| 日本黄在免费看视频| 日韩精品中文字幕福利| 精品欧美一区二区vr在线观看| 国产精品一区二区av国| 久久永久免费精品人妻专区| 日韩近亲视频在线观看| 在线观看操大逼视频| 亚洲av黄色在线网站| 大香蕉大香蕉大香蕉大香蕉大香蕉| 亚洲一区二区人妻av| 国产自拍黄片在线观看| 美女少妇亚洲精选av| 97香蕉碰碰人妻国产樱花| 精品国产污污免费网站入口自| 又粗又硬又猛又爽又黄的| 成年人啪啪视频在线观看| 国产91精品拍在线观看| 美女操逼免费短视频下载链接| 青青青青青青青青青国产精品视频| 人人妻人人澡人人爽人人dvl| 欧美va不卡视频在线观看| 日韩北条麻妃一区在线| 在线播放一区二区三区Av无码| 午夜激情高清在线观看| 六月婷婷激情一区二区三区| 老师啊太大了啊啊啊尻视频| 最新日韩av传媒在线| 午夜在线一区二区免费| 97人妻夜夜爽二区欧美极品| 久久精品亚洲国产av香蕉| 青青青青视频在线播放| 人人妻人人爱人人草| 夜夜骑夜夜操夜夜奸| 99热国产精品666| 国产熟妇乱妇熟色T区| 制丝袜业一区二区三区| 中文字幕综合一区二区| 国产精品一区二区久久久av| 大鸡巴操b视频在线| 中文字幕日韩精品日本| 99热国产精品666| 久久这里只有精品热视频| 92福利视频午夜1000看| 中国把吊插入阴蒂的视频| 夜夜嗨av蜜臀av| 内射久久久久综合网| 亚洲激情偷拍一区二区| 男大肉棒猛烈插女免费视频| 极品丝袜一区二区三区| 91精品国产黑色丝袜| 真实国模和老外性视频| 日本少妇在线视频大香蕉在线观看| 美女小视频网站在线| 1000部国产精品成人观看视频 | 大香蕉玖玖一区2区| 亚洲av午夜免费观看| 日本熟妇一区二区x x| 视频在线免费观看你懂得| aiss午夜免费视频| 午夜免费体验区在线观看| 日韩欧美中文国产在线| 9色在线视频免费观看| 天天爽夜夜爽人人爽QC| 国产精品国产精品一区二区| 女人精品内射国产99| 日韩在线视频观看有码在线| 色天天天天射天天舔| 97瑟瑟超碰在线香蕉| 夜色撩人久久7777| 亚洲欧美自拍另类图片| 人人在线视频一区二区| 国产+亚洲+欧美+另类| 国产剧情演绎系列丝袜高跟| 大陆精品一区二区三区久久| 亚洲一区制服丝袜美腿| 女同互舔一区二区三区| 午夜婷婷在线观看视频| 国产精品污污污久久| 2017亚洲男人天堂| 一区二区久久成人网| 久久久久91精品推荐99| 一区二区三区美女毛片| av破解版在线观看| 一区二区三区视频,福利一区二区| 天堂av中文在线最新版| 57pao国产一区二区| 欧美国产亚洲中英文字幕| 久久久久久九九99精品| 成人网18免费视频版国产| 欧美中国日韩久久精品| 99精品国自产在线人| 2012中文字幕在线高清| 青青草人人妻人人妻| 人妻熟女中文字幕aⅴ在线| 2020韩国午夜女主播在线| 精品91高清在线观看| 啊啊好慢点插舔我逼啊啊啊视频 | 黄网十四区丁香社区激情五月天| 午夜蜜桃一区二区三区| www日韩毛片av| 黄色三级网站免费下载| 欧美精品激情在线最新观看视频| 真实国产乱子伦一区二区| 人妻爱爱 中文字幕| 国产日韩精品电影7777| 亚洲欧美精品综合图片小说| 亚洲一区二区久久久人妻| 特级无码毛片免费视频播放| av男人天堂狠狠干| 亚洲av色图18p| 天美传媒mv视频在线观看| 日美女屁股黄邑视频| 欧美第一页在线免费观看视频| 中国黄色av一级片| 天天插天天狠天天操| 最新的中文字幕 亚洲| 在线新三级黄伊人网| 精品av国产一区二区三区四区 | 亚洲国产免费av一区二区三区 | 91极品大一女神正在播放 | 国产污污污污网站在线| 少妇高潮无套内谢麻豆| tube69日本少妇| 中文字幕 人妻精品| 蝴蝶伊人久久中文娱乐网| 亚洲国产精品免费在线观看| 啊用力插好舒服视频| 日本一二三区不卡无| 精品一区二区三区午夜| 韩国爱爱视频中文字幕| 早川濑里奈av黑人番号| 精品高潮呻吟久久av| 在线观看亚洲人成免费网址| 视频一区二区在线免费播放| 超级av免费观看一区二区三区| av视网站在线观看| 自拍 日韩 欧美激情| 久草电影免费在线观看| 久久久久久久久久久免费女人| sw137 中文字幕 在线| 成年人啪啪视频在线观看| 中文字幕在线乱码一区二区 | 特级欧美插插插插插bbbbb| 日本阿v视频在线免费观看| 欧美精品亚洲精品日韩在线| 九色视频在线观看免费| 久碰精品少妇中文字幕av | 黄色成年网站午夜在线观看 | 国产女孩喷水在线观看| 亚洲高清国产拍青青草原| 97欧洲一区二区精品免费| 天天躁日日躁狠狠躁av麻豆| 亚洲美女美妇久久字幕组| 中文字幕 码 在线视频| 日韩三级黄色片网站| 国产日本欧美亚洲精品视| 国产又色又刺激在线视频 | 国产精品国产三级国产精东| 国产janese在线播放| 午夜久久久久久久99| 国产精品国产三级国产精东 | 亚洲美女美妇久久字幕组| 欧美亚洲一二三区蜜臀| 亚洲欧美日韩视频免费观看| 夏目彩春在线中文字幕| 成年人午夜黄片视频资源| 精品一区二区三区在线观看| 国产真实乱子伦a视频 | 美日韩在线视频免费看| 国产刺激激情美女网站| 午夜av一区二区三区| 午夜久久久久久久99| 91中文字幕免费在线观看| 精品人人人妻人人玩日产欧| 自拍偷拍,中文字幕| 欧美国品一二三产区区别| 91精品啪在线免费| 天天日天天舔天天射进去| 欧美特级特黄a大片免费| 天天色天天爱天天爽| 这里只有精品双飞在线播放| 久草视频在线免播放| 大陆精品一区二区三区久久| 天天干夜夜操啊啊啊| 91超碰青青中文字幕| 国产美女一区在线观看| 中文字幕一区二区三区人妻大片| 亚洲va国产va欧美精品88| 最新97国产在线视频| 欧美va不卡视频在线观看| 白白操白白色在线免费视频| 一个色综合男人天堂| 亚洲精品亚洲人成在线导航| 亚洲欧美在线视频第一页| 亚洲成人三级在线播放| 日本欧美视频在线观看三区| 色综合久久五月色婷婷综合| 动漫av网站18禁| 国产91久久精品一区二区字幕| 亚洲超碰97人人做人人爱| 粉嫩av蜜乳av蜜臀| 蜜桃臀av蜜桃臀av| 中出中文字幕在线观看| 一个色综合男人天堂| 欧美3p在线观看一区二区三区| 亚洲欧美精品综合图片小说| 极品性荡少妇一区二区色欲| 国产白嫩美女一区二区| 姐姐的朋友2在线观看中文字幕 | 亚洲色偷偷综合亚洲AV伊人| 免费在线播放a级片| 在线国产日韩欧美视频| 国产综合精品久久久久蜜臀| 午夜频道成人在线91| 国产无遮挡裸体免费直播视频| av高潮迭起在线观看| 欧亚日韩一区二区三区观看视频| 大香蕉福利在线观看| 亚洲黄色av网站免费播放| 2o22av在线视频| 精品国产乱码一区二区三区乱| av乱码一区二区三区| 国产亚洲四十路五十路| 亚洲欧美一区二区三区电影| 18禁网站一区二区三区四区| 又黄又刺激的午夜小视频| 国产精品午夜国产小视频| 欧洲国产成人精品91铁牛tv| 久久久久久九九99精品| 中文字幕中文字幕人妻| 久久久人妻一区二区| 天天插天天狠天天操| 边摸边做超爽毛片18禁色戒| 黄片大全在线观看观看| 夜夜嗨av一区二区三区中文字幕| 国产日韩精品电影7777| 免费观看理论片完整版| 98视频精品在线观看| 天天日天天干天天搡| 午夜国产免费福利av| 日韩欧美亚洲熟女人妻| 天堂av在线官网中文| 青青青青操在线观看免费| 老司机欧美视频在线看| 亚洲天堂成人在线观看视频网站| 黄片大全在线观看观看| 日本女人一级免费片| 成人影片高清在线观看| 成人高清在线观看视频| 国产三级精品三级在线不卡| 瑟瑟视频在线观看免费视频| 九一传媒制片厂视频在线免费观看| 岛国青草视频在线观看| 黄色无码鸡吧操逼视频| aaa久久久久久久久| 伊人成人在线综合网| www骚国产精品视频| 91麻豆精品传媒国产黄色片| 91精品高清一区二区三区| 午夜在线观看岛国av,com| 亚洲av午夜免费观看| 亚洲综合色在线免费观看| 亚洲一区二区三区久久受| 中文字幕综合一区二区| 中文亚洲欧美日韩无线码| 激情小视频国产在线| 亚洲福利天堂久久久久久| 把腿张开让我插进去视频| 93人妻人人揉人人澡人人| 久草视频在线看免费| 色综合色综合色综合色| 2022中文字幕在线| 国产精品大陆在线2019不卡| 国产伊人免费在线播放| 久久久久五月天丁香社区| 人人爽亚洲av人人爽av| 国产又大又黄免费观看| 欧美精品中文字幕久久二区| 在线观看操大逼视频| 国产高清精品一区二区三区| 国产污污污污网站在线| 国产在线自在拍91国语自产精品| 边摸边做超爽毛片18禁色戒| 夜夜骑夜夜操夜夜奸| 国产剧情演绎系列丝袜高跟| 精品一线二线三线日本| 91人妻精品一区二区在线看| 国产不卡av在线免费| 免费在线福利小视频| 久久精品视频一区二区三区四区| 午夜毛片不卡免费观看视频| 日辽宁老肥女在线观看视频| 青青青视频手机在线观看| 欧洲亚洲欧美日韩综合| 成人影片高清在线观看| 成人24小时免费视频| 青青青aaaa免费| 天堂中文字幕翔田av| 成人av在线资源网站| 亚洲欧美综合另类13p| 韩国爱爱视频中文字幕| 国产97在线视频观看| av老司机亚洲一区二区| 岛国一区二区三区视频在线| 日日夜夜狠狠干视频| 一区国内二区日韩三区欧美| 黑人大几巴狂插日本少妇| 99热久久极品热亚洲| 69精品视频一区二区在线观看| 午夜精品一区二区三区4| aiss午夜免费视频| 在线观看911精品国产| 硬鸡巴动态操女人逼视频| 国产三级精品三级在线不卡| 91免费放福利在线观看| 国产chinesehd精品麻豆| 少妇人妻久久久久视频黄片| 精产国品久久一二三产区区别| 人妻素人精油按摩中出| 日韩欧美高清免费在线| 亚洲综合图片20p| 成人av中文字幕一区| 一区二区三区国产精选在线播放| 97国产在线av精品| 亚洲国产欧美一区二区三区久久| 亚洲熟女久久久36d| 2018最新中文字幕在线观看| 91久久人澡人人添人人爽乱| 成熟丰满熟妇高潮xx×xx| 久久99久久99精品影院| 大香蕉伊人国产在线| 欧美区一区二区三视频| 天天躁日日躁狠狠躁躁欧美av| 97人妻总资源视频| 久久精品在线观看一区二区| 五月天色婷婷在线观看视频免费| 天天想要天天操天天干| av一区二区三区人妻| 精品国产污污免费网站入口自| 日韩av有码中文字幕| 999久久久久999| 岛国一区二区三区视频在线| 97精品成人一区二区三区| 五月婷婷在线观看视频免费 | 五月天中文字幕内射| 亚洲av日韩精品久久久久久hd| 国产女人叫床高潮大片视频| 天美传媒mv视频在线观看| 极品性荡少妇一区二区色欲| 888欧美视频在线| 韩国女主播精品视频网站| 午夜福利人人妻人人澡人人爽 | 亚洲午夜电影之麻豆| 久久久久五月天丁香社区| 国产欧美精品不卡在线| 老司机福利精品免费视频一区二区| 性感美女诱惑福利视频| 亚洲午夜电影在线观看| 绝色少妇高潮3在线观看| 专门看国产熟妇的网站| 视频 国产 精品 熟女 | 丰满的继坶3中文在线观看| 大黑人性xxxxbbbb| 精品视频一区二区三区四区五区| 人人妻人人澡欧美91精品| 精品91高清在线观看| 女同性ⅹxx女同hd| 强行扒开双腿猛烈进入免费版 | 精品少妇一二三视频在线| 国产精品视频男人的天堂| 中文字幕乱码av资源| chinese国产盗摄一区二区| 日韩av有码一区二区三区4| 中文字幕1卡1区2区3区| 日本性感美女三级视频| 欧美精品免费aaaaaa| 免费一级特黄特色大片在线观看| 国产精品系列在线观看一区二区| 精品久久久久久高潮| 成年人免费看在线视频| 国产亚洲视频在线二区| 东京热男人的av天堂| 国产综合精品久久久久蜜臀| 中文字幕第一页国产在线| 超碰97人人澡人人| 亚洲狠狠婷婷综合久久app| 少妇被强干到高潮视频在线观看| 欲满人妻中文字幕在线| 熟女妇女老妇一二三区| 亚洲成a人片777777| 亚洲精品久久综合久| 视频在线亚洲一区二区| 91老熟女连续高潮对白| 国产成人精品av网站| 大陆胖女人与丈夫操b国语高清| 91九色porny国产蝌蚪视频| 18禁网站一区二区三区四区| gogo国模私拍视频| av手机在线免费观看日韩av| 亚洲福利午夜久久久精品电影网| 成人国产激情自拍三区| 91一区精品在线观看| 91在线免费观看成人| 人妻少妇精品久久久久久| 亚洲av无乱一区二区三区性色| 中文字幕一区二区亚洲一区| 日韩中文字幕福利av| 色97视频在线播放| 一本久久精品一区二区| 色97视频在线播放| 国产精品国产精品一区二区| 在线视频免费观看网| 97国产福利小视频合集| 精品人妻伦一二三区久| 91 亚洲视频在线观看| 91啪国自产中文字幕在线| 国产女人被做到高潮免费视频| 欧美一区二区三区啪啪同性| 日本丰满熟妇BBXBBXHD| 国产成人一区二区三区电影网站| 欧美性感尤物人妻在线免费看| 精品人人人妻人人玩日产欧|