index.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <template>
  2. <div :class="prefixCls" :style="getWrapStyle">
  3. <Spin :spinning="loading" size="large" :style="getWrapStyle">
  4. <iframe
  5. :src="frameSrc"
  6. :class="`${prefixCls}__main`"
  7. ref="frameRef"
  8. @load="hideLoading"
  9. ></iframe>
  10. </Spin>
  11. </div>
  12. </template>
  13. <script lang="ts" setup>
  14. import type { CSSProperties } from 'vue';
  15. import { ref, unref, computed, onMounted, onUnmounted } from 'vue';
  16. import { Spin } from 'ant-design-vue';
  17. import { useWindowSizeFn } from '@vben/hooks';
  18. import { propTypes } from '@/utils/propTypes';
  19. import { useDesign } from '@/hooks/web/useDesign';
  20. import { useLayoutHeight } from '@/layouts/default/content/useContentViewHeight';
  21. const emit = defineEmits(['message']);
  22. defineProps({
  23. frameSrc: propTypes.string.def(''),
  24. });
  25. const loading = ref(true);
  26. const topRef = ref(50);
  27. const heightRef = ref(window.innerHeight);
  28. const frameRef = ref<HTMLFrameElement>();
  29. const { headerHeightRef } = useLayoutHeight();
  30. const { prefixCls } = useDesign('iframe-page');
  31. useWindowSizeFn(calcHeight, { wait: 150, immediate: true });
  32. const getWrapStyle = computed((): CSSProperties => {
  33. return {
  34. height: `${unref(heightRef)}px`,
  35. };
  36. });
  37. function calcHeight() {
  38. const iframe = unref(frameRef);
  39. if (!iframe) {
  40. return;
  41. }
  42. const top = headerHeightRef.value;
  43. topRef.value = top;
  44. heightRef.value = window.innerHeight - top;
  45. const clientHeight = document.documentElement.clientHeight - top;
  46. iframe.style.height = `${clientHeight}px`;
  47. }
  48. function hideLoading() {
  49. loading.value = false;
  50. calcHeight();
  51. }
  52. const messageHandler = (e: MessageEvent) => {
  53. emit('message', e.data);
  54. };
  55. const postMessage = (message: any, tragetOrigin: string, transfer?: Transferable[]) => {
  56. const iframe = unref(frameRef);
  57. if (!iframe) return;
  58. iframe.contentWindow?.postMessage(message, tragetOrigin, transfer);
  59. };
  60. const reload = () => {
  61. loading.value = true;
  62. const iframe = frameRef.value;
  63. if (!iframe) return;
  64. iframe.contentWindow?.location.reload();
  65. loading.value = false;
  66. };
  67. onMounted(() => {
  68. window.addEventListener('message', messageHandler);
  69. });
  70. onUnmounted(() => {
  71. window.removeEventListener('message', messageHandler);
  72. });
  73. defineExpose({ postMessage, reload });
  74. </script>
  75. <style lang="less" scoped>
  76. @prefix-cls: ~'@{namespace}-iframe-page';
  77. .@{prefix-cls} {
  78. .ant-spin-nested-loading {
  79. position: relative;
  80. height: 100%;
  81. .ant-spin-container {
  82. width: 100%;
  83. height: 100%;
  84. padding: 10px;
  85. }
  86. }
  87. &__mask {
  88. position: absolute;
  89. top: 0;
  90. left: 0;
  91. width: 100%;
  92. height: 100%;
  93. }
  94. &__main {
  95. box-sizing: border-box;
  96. width: 100%;
  97. height: 100%;
  98. overflow: hidden;
  99. border: 0;
  100. background-color: @component-background;
  101. }
  102. }
  103. </style>