From 74ec002d23e2864f72c023c7d1eb317de96fca70 Mon Sep 17 00:00:00 2001 From: jeremywuuuuu Date: Wed, 23 Jun 2021 16:32:48 +0800 Subject: [PATCH] feat(hooks): feat: Encapsulate function for rendering teleport element - Add new function for rendering teleport element. --- packages/hooks/use-teleport/index.ts | 60 +++++++++++++++++++++++++ packages/popper/src/renderers/popper.ts | 2 +- packages/utils/global-nodes.ts | 34 ++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 packages/hooks/use-teleport/index.ts create mode 100644 packages/utils/global-nodes.ts diff --git a/packages/hooks/use-teleport/index.ts b/packages/hooks/use-teleport/index.ts new file mode 100644 index 0000000000..8720000528 --- /dev/null +++ b/packages/hooks/use-teleport/index.ts @@ -0,0 +1,60 @@ +import { h, ref, Teleport, getCurrentInstance, onMounted } from 'vue' +import { NOOP } from '@vue/shared' +import isServer from '@element-plus/utils/isServer' +import { createGlobalNode, removeGlobalNode } from '@element-plus/utils/global-nodes' + +import type { VNode } from 'vue' + +export default (contentRenderer: () => VNode, appendToBody: boolean) => { + const vm = getCurrentInstance() + + const isTeleportVisible = ref(false) + + if (isServer) { + return { + isTeleportVisible, + showTeleport: NOOP, + hideTeleport: NOOP, + renderTeleport: NOOP, + } + } + + const target = (vm.proxy.$props as { target: string; }).target + let $el: HTMLElement = null + + const showTeleport = () => { + + isTeleportVisible.value = true + $el = createGlobalNode() + } + + const hideTeleport = () => { + + isTeleportVisible.value = true + removeGlobalNode($el) + $el = null + } + + const renderTeleport = () => { + return appendToBody !== true + ? contentRenderer() + : isTeleportVisible.value === true + ? [ + h( + Teleport, + { to: target }, + contentRenderer(), + ), + ] + : void 0 + } + + onMounted(hideTeleport) + + return { + isTeleportVisible, + showTeleport, + hideTeleport, + renderTeleport, + } +} diff --git a/packages/popper/src/renderers/popper.ts b/packages/popper/src/renderers/popper.ts index 7a5b005abe..b02182c2d6 100644 --- a/packages/popper/src/renderers/popper.ts +++ b/packages/popper/src/renderers/popper.ts @@ -3,7 +3,7 @@ import { NOOP } from '@vue/shared' import { stop } from '@element-plus/utils/dom' import type { VNode, Ref } from 'vue' -import type { Effect } from '../use-popper/defaults' +import type { Effect } from '@element-plus/internal/props/use-popper-props' interface IRenderPopperProps { effect: Effect diff --git a/packages/utils/global-nodes.ts b/packages/utils/global-nodes.ts new file mode 100644 index 0000000000..e409d3546b --- /dev/null +++ b/packages/utils/global-nodes.ts @@ -0,0 +1,34 @@ +import isServer from './isServer' + +const globalNodes = [] +let target = isServer ? void 0 : document.body + +export function createGlobalNode(id?: string) { + const el = document.createElement('div') + + if (id !== void 0) { + el.id = id + } + + target.appendChild(el) + globalNodes.push(el) + + return el +} + +export function removeGlobalNode(el: HTMLElement) { + globalNodes.splice(globalNodes.indexOf(el), 1) + el.remove() +} + +export function changeGlobalNodesTarget(el: HTMLElement) { + if (el !== target) { + target = el + + globalNodes.forEach(el => { + if (el.contains(target) === false) { + target.appendChild(el) + } + }) + } +}