index.ts 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import { Teleport, h, onUnmounted, ref } from 'vue'
  2. import { NOOP } from '@vue/shared'
  3. import { isClient } from '@vueuse/core'
  4. import { createGlobalNode, removeGlobalNode } from '@element-plus/utils'
  5. import type { Ref, VNode } from 'vue'
  6. export const useTeleport = (
  7. contentRenderer: () => VNode,
  8. appendToBody: Ref<boolean>
  9. ) => {
  10. const isTeleportVisible = ref(false)
  11. if (!isClient) {
  12. return {
  13. isTeleportVisible,
  14. showTeleport: NOOP,
  15. hideTeleport: NOOP,
  16. renderTeleport: NOOP,
  17. }
  18. }
  19. let $el: HTMLElement | null = null
  20. const showTeleport = () => {
  21. isTeleportVisible.value = true
  22. // this allows the delayed showing strategy since the the content itself could be enterable
  23. // e.g. el-popper
  24. if ($el !== null) return
  25. $el = createGlobalNode()
  26. }
  27. const hideTeleport = () => {
  28. isTeleportVisible.value = false
  29. if ($el !== null) {
  30. removeGlobalNode($el)
  31. $el = null
  32. }
  33. }
  34. const renderTeleport = () => {
  35. return appendToBody.value !== true
  36. ? contentRenderer()
  37. : isTeleportVisible.value
  38. ? [h(Teleport, { to: $el }, contentRenderer())]
  39. : undefined
  40. }
  41. onUnmounted(hideTeleport)
  42. return {
  43. isTeleportVisible,
  44. showTeleport,
  45. hideTeleport,
  46. renderTeleport,
  47. }
  48. }