這篇文章將為大家詳細講解有關(guān)Vue3中Teleport 組件的原理是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
運城網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)公司!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)公司公司2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)公司。
使用場景
業(yè)務(wù)開發(fā)的過程中,我們經(jīng)常會封裝一些常用的組件,例如 Modal 組件。相信大家在使用 Modal 組件的過程中,經(jīng)常會遇到一個問題,那就是 Modal 的定位問題。
話不多說,我們先寫一個簡單的 Modal 組件。
彈窗標題
x彈窗文本內(nèi)容
然后我們在頁面中引入 Modal 組件。
Modal
如上圖所示, div.container 下彈窗組件正常展示。使用 fixed 進行布局的元素,在一般情況下會相對于屏幕視窗來進行定位,但是如果父元素的 transform, perspective 或 filter 屬性不為 none 時,fixed 元素就會相對于父元素來進行定位。
我們只需要把 .container 類的 transform 稍作修改,彈窗組件的定位就會錯亂。
Modal
這個時候,使用 Teleport 組件就能解決這個問題了。
“Teleport 提供了一種干凈的方法,允許我們控制在 DOM 中哪個父節(jié)點下呈現(xiàn) HTML,而不必求助于全局狀態(tài)或?qū)⑵洳鸱譃閮蓚€組件。-- Vue 官方文檔
我們只需要將彈窗內(nèi)容放入 Teleport 內(nèi),并設(shè)置 to 屬性為 body,表示彈窗組件每次渲染都會做為 body 的子級,這樣之前的問題就能得到解決。
...
可以在 https://codesandbox.io/embed/vue-modal-h6g8y 查看代碼。
使用 Teleport 的 Modal
源碼解析
我們可以先寫一個簡單的模板,然后看看 Teleport 組件經(jīng)過模板編譯后,生成的代碼。
Vue.createApp({ template: `` }) teleport to body
模板編譯后的代碼
簡化后代碼:
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 進行創(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 的第一個參數(shù)為 Teleport,最后得到的 vnode 中會有一個 shapeFlag 屬性,該屬性用來表示 vnode 的類型。isTeleport(type) 得到的結(jié)果為 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 節(jié)點,會依據(jù) 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 是之前已創(chuàng)建組件的緩存 patch(container._vnode || null, vnode, container) } container._vnode = vnode } // patch 是表示補丁,用于 vnode 的創(chuàng)建、更新、銷毀 const patch = (n1, n2, container) => { // 如果新舊節(jié)點的類型不一致,則將舊節(jié)點銷毀 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 時,最后會調(diào)用 Teleport.process 方法,Vue3 中很多地方都是通過 process 的方式來處理 vnode 相關(guā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) { // 開關(guān)關(guān)閉,掛載到原來的位置 mount(container) } else if (target) { // 將子節(jié)點,掛載到屬性 `to` 對應(yīng)的節(jié)點上 mount(target) } } else { // n1不存在,更新節(jié)點即可 } } }
其實原理很簡單,就是將 Teleport 的 children 掛載到屬性 to 對應(yīng)的 DOM 元素中。為了方便理解,這里只是展示了源碼的九牛一毛,省略了很多其他的操作。
關(guān)于Vue3中Teleport 組件的原理是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。