中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue3中Teleport 組件的原理是什么

發布時間:2021-07-09 11:11:47 來源:億速云 閱讀:183 作者:Leah 欄目:web開發

這篇文章將為大家詳細講解有關Vue3中Teleport 組件的原理是什么,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

使用場景

業務開發的過程中,我們經常會封裝一些常用的組件,例如 Modal 組件。相信大家在使用 Modal 組件的過程中,經常會遇到一個問題,那就是 Modal  的定位問題。

話不多說,我們先寫一個簡單的 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">         <h4 class="modal__title">彈窗標題</h4>         <span class="modal__close">x</span>       </div>       <div class="modal__content">         彈窗文本內容       </div>       <div class="modal__footer">         <button>取消</button>         <button>確認</button>       </div>     </div>   </div> </template>  <script> export default {   setup() {     return {};   }, }; </script>

然后我們在頁面中引入 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>

Vue3中Teleport 組件的原理是什么

Modal

如上圖所示, div.container 下彈窗組件正常展示。使用 fixed 進行布局的元素,在一般情況下會相對于屏幕視窗來進行定位,但是如果父元素的  transform, perspective 或 filter 屬性不為 none 時,fixed 元素就會相對于父元素來進行定位。

我們只需要把 .container 類的 transform 稍作修改,彈窗組件的定位就會錯亂。

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

Vue3中Teleport 組件的原理是什么

Modal

這個時候,使用 Teleport 組件就能解決這個問題了。

“Teleport 提供了一種干凈的方法,允許我們控制在 DOM 中哪個父節點下呈現 HTML,而不必求助于全局狀態或將其拆分為兩個組件。-- Vue  官方文檔

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

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

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

Vue3中Teleport 組件的原理是什么

使用 Teleport 的 Modal

源碼解析

我們可以先寫一個簡單的模板,然后看看 Teleport 組件經過模板編譯后,生成的代碼。

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

Vue3中Teleport 組件的原理是什么

模板編譯后的代碼

簡化后代碼:

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 組件通過 createBlock 進行創建。

// 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 的第一個參數為 Teleport,最后得到的 vnode 中會有一個 shapeFlag 屬性,該屬性用來表示 vnode  的類型。isTeleport(type) 得到的結果為 true,所以 shapeFlag 屬性最后的值為 ShapeFlags.TELEPORT(1  << 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 節點,會依據 type 和 shapeFlag 走不同的邏輯。

// packages/runtime-core/src/renderer.ts const render = (vnode, container) => {   if (vnode == null) {     // 當前組件為空,則將組件銷毀     if (container._vnode) {       unmount(container._vnode, null, null, true)     }   } else {     // 新建或者更新組件     // container._vnode 是之前已創建組件的緩存     patch(container._vnode || null, vnode, container)   }   container._vnode = vnode }  // patch 是表示補丁,用于 vnode 的創建、更新、銷毀 const patch = (n1, n2, container) => {   // 如果新舊節點的類型不一致,則將舊節點銷毀   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 組件         // 調用 Teleport.process 方法         type.process(n1, n2, container...);       } // else if ...   } }

可以看到,在處理 Teleport 時,最后會調用 Teleport.process 方法,Vue3 中很多地方都是通過 process 的方式來處理  vnode 相關邏輯的,下面我們重點看看 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) {         // 開關關閉,掛載到原來的位置         mount(container)       } else if (target) {         // 將子節點,掛載到屬性 `to` 對應的節點上         mount(target)       }     }     else {       // n1不存在,更新節點即可     }   } }

其實原理很簡單,就是將 Teleport 的 children 掛載到屬性 to 對應的 DOM  元素中。為了方便理解,這里只是展示了源碼的九牛一毛,省略了很多其他的操作。

關于Vue3中Teleport 組件的原理是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

民权县| 潞西市| 门源| 泸溪县| 黑水县| 库车县| 铜川市| 淮安市| 普兰县| 兖州市| 界首市| 巴南区| 伊川县| 德格县| 勐海县| 正宁县| 阿瓦提县| 陆川县| 双桥区| 蕲春县| 许昌县| 三穗县| 南乐县| 阜阳市| 保定市| 赞皇县| 普安县| 资兴市| 容城县| 华池县| 金门县| 安西县| 苍溪县| 沧源| 日土县| 合肥市| 加查县| 浙江省| 麟游县| 伊金霍洛旗| 青河县|