亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Vue3 Teleport 的實(shí)踐及原理

 更新時(shí)間:2020年12月02日 10:46:35   作者:Shenfq  
這篇文章主要介紹了Vue3 Teleport 組件的實(shí)踐及原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

Vue3 的組合式 API 以及基于 Proxy 響應(yīng)式原理已經(jīng)有很多文章介紹過(guò)了,除了這些比較亮眼的更新,Vue3 還新增了一個(gè)內(nèi)置組件: Teleport 。這個(gè)組件的作用主要用來(lái)將模板內(nèi)的 DOM 元素移動(dòng)到其他位置。

使用場(chǎng)景

業(yè)務(wù)開(kāi)發(fā)的過(guò)程中,我們經(jīng)常會(huì)封裝一些常用的組件,例如 Modal 組件。相信大家在使用 Modal 組件的過(guò)程中,經(jīng)常會(huì)遇到一個(gè)問(wèn)題,那就是 Modal 的定位問(wèn)題。

話(huà)不多說(shuō),我們先寫(xiě)一個(gè)簡(jiǎn)單的 Modal 組件。

<!-- Modal.vue -->
<style lang="scss">
.modal {
 &__mask {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.5);
 }
 &__main {
  margin: 0 auto;
  margin-bottom: 5%;
  margin-top: 20%;
  width: 500px;
  background: #fff;
  border-radius: 8px;
 }
 /* 省略部分樣式 */
}
</style>
<template>
 <div class="modal__mask">
  <div class="modal__main">
   <div class="modal__header">
    <h3 class="modal__title">彈窗標(biāo)題</h3>
    <span class="modal__close">x</span>
   </div>
   <div class="modal__content">
    彈窗文本內(nèi)容
   </div>
   <div class="modal__footer">
    <button>取消</button>
    <button>確認(rèn)</button>
   </div>
  </div>
 </div>
</template>

<script>
export default {
 setup() {
  return {};
 },
};
</script>

然后我們?cè)陧?yè)面中引入 Modal 組件。

<!-- App.vue -->
<style lang="scss">
.container {
 height: 80vh;
 margin: 50px;
 overflow: hidden;
}
</style>
<template>
 <div class="container">
  <Modal />
 </div>
</template>

<script>
export default {
 components: {
  Modal,
 },
 setup() {
  return {};
 }
};
</script>

如上圖所示, div.container 下彈窗組件正常展示。使用 fixed 進(jìn)行布局的元素,在一般情況下會(huì)相對(duì)于屏幕視窗來(lái)進(jìn)行定位,但是如果父元素的 transform , perspectivefilter 屬性不為 none 時(shí), fixed 元素就會(huì)相對(duì)于父元素來(lái)進(jìn)行定位。

我們只需要把 .container 類(lèi)的 transform 稍作修改,彈窗組件的定位就會(huì)錯(cuò)亂。

<style lang="scss">
.container {
 height: 80vh;
 margin: 50px;
 overflow: hidden;
 transform: translateZ(0);
}
</style>

這個(gè)時(shí)候,使用 Teleport 組件就能解決這個(gè)問(wèn)題了。

Teleport 提供了一種干凈的方法,允許我們控制在 DOM 中哪個(gè)父節(jié)點(diǎn)下呈現(xiàn) HTML,而不必求助于全局狀態(tài)或?qū)⑵洳鸱譃閮蓚€(gè)組件。 -- Vue 官方文檔

我們只需要將彈窗內(nèi)容放入 Teleport 內(nèi),并設(shè)置 to 屬性為 body ,表示彈窗組件每次渲染都會(huì)做為 body 的子級(jí),這樣之前的問(wèn)題就能得到解決。

<template>
 <teleport to="body">
  <div class="modal__mask">
   <div class="modal__main">
    ...
   </div>
  </div>
 </teleport>
</template>

可以在 https://codesandbox.io/embed/vue-modal-h5g8y 查看代碼。

源碼解析

我們可以先寫(xiě)一個(gè)簡(jiǎn)單的模板,然后看看 Teleport 組件經(jīng)過(guò)模板編譯后,生成的代碼。

Vue.createApp({
 template: `
  <Teleport to="body">
   <div> teleport to body </div> 
  </Teleport>
 `
})

簡(jiǎn)化后代碼:

function render(_ctx, _cache) {
 with (_ctx) {
  const { createVNode, openBlock, createBlock, Teleport } = Vue
  return (openBlock(), createBlock(Teleport, { to: "body" }, [
   createVNode("div", null, " teleport to body ", -1 /* HOISTED */)
  ]))
 }
}

可以看到 Teleport 組件通過(guò) createBlock 進(jìn)行創(chuàng)建。

// packages/runtime-core/src/renderer.ts
export function createBlock(
  type, props, children, patchFlag
) {
 const vnode = createVNode(
  type,
  props,
  children,
  patchFlag
 )
 // ... 省略部分邏輯
 return vnode
}

export function createVNode(
 type, props, children, patchFlag
) {
 // class & style normalization.
 if (props) {
  // ...
 }

 // encode the vnode type information into a bitmap
 const shapeFlag = isString(type)
  ? ShapeFlags.ELEMENT
  : __FEATURE_SUSPENSE__ && isSuspense(type)
   ? ShapeFlags.SUSPENSE
   : isTeleport(type)
    ? ShapeFlags.TELEPORT
    : isObject(type)
     ? ShapeFlags.STATEFUL_COMPONENT
     : isFunction(type)
      ? ShapeFlags.FUNCTIONAL_COMPONENT
      : 0

 const vnode: VNode = {
  type,
  props,
  shapeFlag,
  patchFlag,
  key: props && normalizeKey(props),
  ref: props && normalizeRef(props),
 }

 return vnode
}

// packages/runtime-core/src/components/Teleport.ts
export const isTeleport = type => type.__isTeleport
export const Teleport = {
 __isTeleport: true,
 process() {}
}

傳入 createBlock 的第一個(gè)參數(shù)為 Teleport ,最后得到的 vnode 中會(huì)有一個(gè) shapeFlag 屬性,該屬性用來(lái)表示 vnode 的類(lèi)型。 isTeleport(type) 得到的結(jié)果為 true ,所以 shapeFlag 屬性最后的值為 ShapeFlags.TELEPORT1 << 6 )。

// packages/shared/src/shapeFlags.ts
export const enum ShapeFlags {
 ELEMENT = 1,
 FUNCTIONAL_COMPONENT = 1 << 1,
 STATEFUL_COMPONENT = 1 << 2,
 TEXT_CHILDREN = 1 << 3,
 ARRAY_CHILDREN = 1 << 4,
 SLOTS_CHILDREN = 1 << 5,
 TELEPORT = 1 << 6,
 SUSPENSE = 1 << 7,
 COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
 COMPONENT_KEPT_ALIVE = 1 << 9
}

在組件的 render 節(jié)點(diǎn),會(huì)依據(jù) typeshapeFlag 走不同的邏輯。

// packages/runtime-core/src/renderer.ts
const render = (vnode, container) => {
 if (vnode == null) {
  // 當(dāng)前組件為空,則將組件銷(xiāo)毀
  if (container._vnode) {
   unmount(container._vnode, null, null, true)
  }
 } else {
  // 新建或者更新組件
  // container._vnode 是之前已創(chuàng)建組件的緩存
  patch(container._vnode || null, vnode, container)
 }
 container._vnode = vnode
}

// patch 是表示補(bǔ)丁,用于 vnode 的創(chuàng)建、更新、銷(xiāo)毀
const patch = (n1, n2, container) => {
 // 如果新舊節(jié)點(diǎn)的類(lèi)型不一致,則將舊節(jié)點(diǎn)銷(xiāo)毀
 if (n1 && !isSameVNodeType(n1, n2)) {
  unmount(n1)
 }
 const { type, ref, shapeFlag } = n2
 switch (type) {
  case Text:
   // 處理文本
   break
  case Comment:
   // 處理注釋
   break
  // case ...
  default:
   if (shapeFlag & ShapeFlags.ELEMENT) {
    // 處理 DOM 元素
   } else if (shapeFlag & ShapeFlags.COMPONENT) {
    // 處理自定義組件
   } else if (shapeFlag & ShapeFlags.TELEPORT) {
    // 處理 Teleport 組件
    // 調(diào)用 Teleport.process 方法
    type.process(n1, n2, container...);
   } // else if ...
 }
}

可以看到,在處理 Teleport 時(shí),最后會(huì)調(diào)用 Teleport.process 方法,Vue3 中很多地方都是通過(guò) process 的方式來(lái)處理 vnode 相關(guān)邏輯的,下面我們重點(diǎn)看看 Teleport.process 方法做了些什么。

// packages/runtime-core/src/components/Teleport.ts
const isTeleportDisabled = props => props.disabled
export const Teleport = {
 __isTeleport: true,
 process(n1, n2, container) {
  const disabled = isTeleportDisabled(n2.props)
  const { shapeFlag, children } = n2
  if (n1 == null) {
   const target = (n2.target = querySelector(n2.prop.to))   
   const mount = (container) => {
    // compiler and vnode children normalization.
    if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
     mountChildren(children, container)
    }
   }
   if (disabled) {
    // 開(kāi)關(guān)關(guān)閉,掛載到原來(lái)的位置
    mount(container)
   } else if (target) {
    // 將子節(jié)點(diǎn),掛載到屬性 `to` 對(duì)應(yīng)的節(jié)點(diǎn)上
    mount(target)
   }
  }
  else {
   // n1不存在,更新節(jié)點(diǎn)即可
  }
 }
}

其實(shí)原理很簡(jiǎn)單,就是將 Teleportchildren 掛載到屬性 to 對(duì)應(yīng)的 DOM 元素中。為了方便理解,這里只是展示了源碼的九牛一毛,省略了很多其他的操作。

總結(jié)

希望在閱讀文章的過(guò)程中,大家能夠掌握 Teleport 組件的用法,并使用到業(yè)務(wù)場(chǎng)景中。盡管原理十分簡(jiǎn)單,但是我們有了 Teleport 組件,就能輕松解決彈窗元素定位不準(zhǔn)確的問(wèn)題。

到此這篇關(guān)于詳解Vue3 Teleport 的實(shí)踐及原理的文章就介紹到這了,更多相關(guān)Vue3 Teleport組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue prop屬性傳值與傳引用示例

    vue prop屬性傳值與傳引用示例

    今天小編就為大家分享一篇vue prop屬性傳值與傳引用示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • 解決vue項(xiàng)目運(yùn)行出現(xiàn)warnings?potentially?fixable?with?the?`--fix`?option的報(bào)錯(cuò)問(wèn)題

    解決vue項(xiàng)目運(yùn)行出現(xiàn)warnings?potentially?fixable?with?the?`--fix

    這篇文章主要介紹了解決vue項(xiàng)目運(yùn)行出現(xiàn)warnings?potentially?fixable?with?the?`--fix`?option的報(bào)錯(cuò)問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-11-11
  • Vue處理循環(huán)數(shù)據(jù)流程示例精講

    Vue處理循環(huán)數(shù)據(jù)流程示例精講

    這篇文章主要介紹了Vue處理循環(huán)數(shù)據(jù)流程,這個(gè)又是一個(gè)編程語(yǔ)言,?模版語(yǔ)法里面必不可少的一個(gè),?也是使用業(yè)務(wù)場(chǎng)景使用最多的一個(gè)環(huán)節(jié)。所以學(xué)會(huì)使用循環(huán)也是重中之重了
    2023-04-04
  • vue獲取v-for異步數(shù)據(jù)dom的解決問(wèn)題

    vue獲取v-for異步數(shù)據(jù)dom的解決問(wèn)題

    這篇文章主要介紹了vue獲取v-for異步數(shù)據(jù)dom的解決問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • vue2 webpack proxy與nginx配置方式

    vue2 webpack proxy與nginx配置方式

    這篇文章主要介紹了vue2 webpack proxy與nginx配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Vue中通過(guò)vue-router實(shí)現(xiàn)命名視圖的問(wèn)題

    Vue中通過(guò)vue-router實(shí)現(xiàn)命名視圖的問(wèn)題

    這篇文章主要介紹了在Vue中通過(guò)vue-router實(shí)現(xiàn)命名視圖,本文給大家提到了vue-router的原理解析,給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • vue項(xiàng)目中路由懶加載的三種方式(簡(jiǎn)潔易懂)

    vue項(xiàng)目中路由懶加載的三種方式(簡(jiǎn)潔易懂)

    本文主要介紹了vue項(xiàng)目中路由懶加載的三種方式,主要包括vue異步組件,組件懶加載,webpack的require.ensure(),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • vue-quill-editor 自定義工具欄和自定義圖片上傳路徑操作

    vue-quill-editor 自定義工具欄和自定義圖片上傳路徑操作

    這篇文章主要介紹了vue-quill-editor 自定義工具欄和自定義圖片上傳路徑操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • vue使用less報(bào)錯(cuò):Inline JavaScript is not enabled問(wèn)題

    vue使用less報(bào)錯(cuò):Inline JavaScript is not ena

    這篇文章主要介紹了vue使用less報(bào)錯(cuò):Inline JavaScript is not enabled問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • vue3限制table表格選項(xiàng)個(gè)數(shù)的解決方法

    vue3限制table表格選項(xiàng)個(gè)數(shù)的解決方法

    這篇文章主要為大家詳細(xì)介紹了vue3限制table表格選項(xiàng)個(gè)數(shù)的解決方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評(píng)論