• 跨域 iframe 隐藏页面元素,高度自适应


    技术栈

    系统 A 和系统 B 均使用 vue2 

    需求

    A 中嵌入 B 系统页面,两种情况

    1、去掉页面 header、footer,仅保留页面主体

    2、保留 header,去掉 footer、header 中 logo、用户信息

    禁用 iframe 中滚动,iframe 窗体高度与 B 中页面一致,使用浏览器滚动条

    1 隐藏元素

    方案制定

    域名不同存在跨域,无法在 A 中直接操作 B 中元素,需 B 系统开发者提供支持

    iframe 加载之后,给 B 发送消息,B 接收到后将元素隐藏

    实现

    A 系统,展示 iframe 的 vue 文件

     1 <template lang="pug">
     2 .iframe-box
     3     iframe(id="iframeInstance" name="iframeInstance" src="http://localhost:8008" scrolling="auto" frameborder="no" seamless ref="iframe" width="100%" height="600")
     4 </template>
     5 
     6 <script>
     7 export default {
     8     async mounted() {
     9         await this.$nextTick()
    10         this.$refs.iframe.addEventListener('load', this.onIframeLoad) // 给 iframe 绑定监听事件
    11     },
    12 
    13     methods: {
    14         onIframeLoad() {
    15             console.log('onload')
    16             this.$refs.iframe.contentWindow.postMessage({ header: false }, '*') // 加载完成之后发送消息,已知目标地址时不要用*,这里的 false 和 true 对应上述需求中两种情况
    17         }
    18     },
    19 }
    20 </script>

    B 系统,App.vue

     1 mounted () {
     2     window.addEventListener('message', (event) => {
     3         // 判断消息来源
     4         const arr = ['xxx.com', 'xxxx.com', 'xxx.cn']
     5         const flag = arr.some(item => event.origin.includes(item))
     6         if (!flag) return
     7 
     8         console.log('message', event.data)
     9 
    10         // 如果两个系统不是单点登录同步登录信息,可以接收用户信息后登录
    11         if (this.$store.getters.unLogin) {
    12             // login
    13         }
    14 
    15         // 隐藏 footer
    16         const footer = document.querySelector('#app .footer')
    17         footer.style.display = 'none'
    18 
    19         // 根据接收的消息隐藏对应元素
    20         if (event.data.header) {
    21             const logo = document.querySelector('#app .header .logo')
    22             const user = document.querySelector('#app .header .user-info')
    23             logo.style.display = 'none'
    24             user.style.display = 'none'
    25         } else {
    26             const header = document.querySelector('#app .header')
    27             header.style.display = 'none'
    28         }
    29     }, false);
    30 }

    2 高度自适应

    方案

    受跨域限制,B 提供高度,A 接收后调整 iframe height 属性

    考虑到展示内容可能收到 tab 切换和过滤条件等影响,通过路由守卫发送消息不满足需求,采用 MutationObserver,监听根元素和子元素

    实现

    A系统,iframe 展示的 vue 文件

     1 <template lang="pug">
     2 .i-iframe
     3     iframe(id="iframeInstance" name="iframeInstance" src="http://localhost:8008" scrolling="no" frameborder="no" seamless ref="iframe" width="100%" :height="height")
     4 </template>
     5 
     6 <script>
     7     export default {
     8         data() {
     9             return {
    10                 height: 600,
    11             }
    12         },
    13 
    14         async mounted() {
    15             await this.$nextTick()
    16             this.$refs.iframe.addEventListener('load', this.onIframeLoad)
    17         },
    18 
    19         created() {
    20             window.addEventListener('message', event => {
    21                 const height = event.data.height || 800
    22                 if(this.height === height) return
    23                 this.height = height
    24             }, false)
    25         },
    26 
    27         methods: {
    28             onIframeLoad() {
    29                 console.log('onload')
    30                 this.$refs.iframe.contentWindow.postMessage({ header: true }, '*')
    31             },
    32         },
    33     }
    34 </script>

    B 系统,App.vue

     1 mounted () {
     2     // 可以写成个方法放 methods 里,这里为了方便展示执行时机就不改了
     3     const targetNode = document.getElementById('app');
     4     const config = { attributes: false, childList: true, subtree: true };
     5     
     6     // 加防抖,避免多次触发
     7     const callback = debounce(() => {
     8         // B 系统设置了 min-height: 100%,过滤条件变化,数据量减少时,由于展示空间足够,高度仍保持上一次的,在这里做一次初始化
     9         window.parent.postMessage({ height: undefined }, '*');
    10 
    11         // 渲染完成后提供最新的页面高度
    12         setTimeout(() => {
    13             window.parent.postMessage({ height: targetNode.offsetHeight }, '*');
    14         }, 70);
    15     }, 300)
    16 
    17     const Mutation =
    18         window.MutationObserver ||
    19         window.WebKitMutationObserver ||
    20         window.MozMutationObserver;
    21     this.observer = new Mutation(callback);
    22     this.observer.observe(targetNode, config);
    23 },
    24 
    25 beforeDestroy () {
    26     if(this.observer) {
    27       this.observer.disconnect()
    28       this.observer = null
    29     }
    30 }

    补充

    此需求中 A、B 两系统使用单点登录,自动同步登录信息。如有同步登录态信息需求,可参考隐藏元素实现代码

    A 传递消息时,增加用户信息。B 接收后执行登录操作

    B 系统登出时,传递消息给 A 系统,A 决定跳转登录页或其他操作

    本文地址:https://www.cnblogs.com/veinyin/p/15745856.html

    感谢您的阅读及指正,让我们一起进步。
    欢迎联系我交流:veinyin@gmail.com
    作者:yuhui_yin
    博客地址:https://www.cnblogs.com/veinyin/
    如转载请注明出处。
  • 相关阅读:
    Tomcat安装配置
    重新捡起手中的笔
    如何拥有一套自己的信用卡分销系统
    关于信用卡分销系统的简单介绍
    jQuery 基础教程(第3版) ---第十章习题答案
    jQuery 基础教程(第3版) ---第九章习题答案
    jQuery 基础教程(第3版) ---第八章习题答案
    jQuery 基础教程(第3版) ---第七章习题答案
    jQuery 基础教程(第3版) ---第六章习题答案
    jQuery 基础教程(第3版) ---第五章习题答案
  • 原文地址:https://www.cnblogs.com/veinyin/p/15745856.html
Copyright © 2020-2023  润新知