美文网首页
2020-05-14 Vue 解决iframe跨域通信后子页面获

2020-05-14 Vue 解决iframe跨域通信后子页面获

作者: 追寻1989 | 来源:发表于2020-05-14 02:23 被阅读0次

    (一)主页面

    1.解决跨域通信

    2.解决iframe每次url改变都能及时显示不产生缓存导致空白页(请详细查看 forceUpdataIframe() 里的代码)

    3.解决iframe的onload每次url改变都能触发(请详细查看 watch()、mounted() 里的代码)

    4.解决子页面获取token后未能及时刷新自动登录问题(请详细查看 iframe.onload()、 sendToken() 里的代码)

    5.解决准确友好的子页面加载状态提示(请详细查看 iframeInit() 里的代码)

    <template>
      <div id="iframeBox">
        <iframe ref="iframe" name="refresh_name" class="iframe-style" frameborder="no" border="0" />
      </div>
    </template>
    
    <script>
    import { getToken, setToken } from "@/utils/auth";
    
    export default {
      name: "Iframe",
      props: {
        url: {
          type: String,
          default: "" // 先用hsa的这个页面
        }
      },
      data() {
        return {
          loading: null,
          myInterVal: null
        };
      },
      watch: {
        url(newVal, oldVal) {
          if (getToken()) {
            // console.log(JSON.stringify(getToken()), "后台管理系统的的getToken");
            this.iframeInit(newVal);
          }
        }
      },
      created() {},
      mounted() {
        this.iframeInit(
          ""
          // 默认打开为空白页
          // https://xxx.xxxxx.com/hsa-local-test/web/uscCenterLocal/#/MenuManage
        );
      },
      methods: {
        sendToken(newVal) {
          // // debugger;
          const iframe = this.$refs.iframe;
          //发送消息
          iframe.contentWindow.postMessage(JSON.stringify(getToken()), "*");
          //触发刷新
          iframe.src = newVal;
          //关闭加载
          this.loading.close();
        },
        //iframe 初始化
        iframeInit(newVal) {
          //链接为空不显示加载状态和绑定ifram监听事件
          if (newVal == "") {
            return;
          }
          // debugger;
          if (this.loading) {
            this.loading.close();
          }
          this.loading = this.$loading({
            target: "#iframeBox",
            lock: true,
            customClass: "global-loading",
            text: "页面加载中...",
            spinner: "el-icon-loading",
            background: "transparent"
          });
          let iframe = this.$refs.iframe;
    
          // 处理兼容行问题
          if (iframe.attachEvent) {
            iframe.attachEvent("onload", () => {
              // debugger;
              this.sendToken(newVal);
            });
          } else {
            iframe.onload = () => {
              // debugger;
              console.log("isOnLoad");
              this.sendToken(newVal);
            };
          }
    
          // 接受子级返回数据
          window.addEventListener(
            "message",
            function(e) {
              // console.log("父级接收子级返回数据" + e.data);
              if (typeof e.data === "string") {
                setToken(JSON.parse(e.data));
              }
            },
            false
          );
    
          //利用异步延迟加载和链接随机传参来达到刷新iframe缓存的目的,不加此步骤iframe页面不更新
          this.forceUpdataIframe(iframe, newVal);
    
          // debugger;
        },
        //强制刷新iframe缓存
        forceUpdataIframe(iframe, newVal) {
          setTimeout(() => {
            let fresh_link =
              new Date().getTime() + Math.floor(Math.random() * 1000000); //获取当前时间戳
            String.prototype.splice = function(start, newStr) {
              return this.slice(0, start) + newStr + this.slice(start);
            };
            let strIndex = newVal.indexOf("/#/");
            let url = newVal.splice(strIndex, "?time=" + fresh_link);
            console.log("url", url);
            iframe.src = url;
            // window.open(newVal + "?time=" + fresh_link, "refresh_name");
          }, 300);
        }
      }
    };
    </script>
    
    <style scoped>
    .iframe-style {
      /*100 = 顶部菜单+标签栏  */
      min-height: calc(100vh - 85px);
      width: 100%;
      position: relative;
      overflow: hidden;
      box-shadow: 1px 1px 1px #eee;
      /* margin: 16px 0 0 16px; */
    }
    </style>
    

    (二)子页面

    1.接收父级 token 并存储 token

    newPromise.js

    import {
      setToken, getToken
    } from '@/utils/auth'
    const promise = function () {
      return new Promise(async (resolve, reject) => {
        if (!getToken()) {
          window.addEventListener('message', function (e) {
            if ((typeof e.data) === 'string') {
              setToken(JSON.parse(e.data));
              resolve(true)
            }
             // resolve(true) //说明 本地联调的时候开启 发布的时候要去掉
          })
        } else {
          resolve(true)
        }
      })
    }
    
    export default promise
    

    2.token过期时调用后端接口刷新 token ,并向父级发送 token 更新信息,让父级保存新token

    request.js

    import axios from 'axios'
    import {
      setToken, getToken
    } from '@/utils/auth'
    
    const service = axios.create({
    ...
    })
    // request interceptor
    service.interceptors.request.use(config => {
    ...
    })
    
    // response interceptor
    service.interceptors.response.use(
      response => {
        const res = response.data
        if (res.code === 600003) {
          refresh({ refreshToken: JSON.parse(getToken()).refreshToken || '' }).then(res => {
            debugger
            if (res.code === 0) {
              let token = {
                'accessToken': data.accessToken,
                'refreshToken': data.refreshToken
              }
              setToken(token)//保存账户actoken和refreshToken
              window.parent.postMessage(JSON.stringify(getToken()), '*')//子页面向父页面发送消息
              setTimeout(() => {
                window.location.reload()
              }, 1200)
            }
          })
        } 
        return res
      }
    )
    

    3.挂载实例前调用接收消息

    main.js

    import promise from './newPromise.js'
    // 挂载实例前调用接收消息
    promise().then(() => {
      new Vue({
        el: '#app',
        router,
        store,
        render: h => h(App)
      })
    })
    

    (三)另附:auth.js

    token工具类函数封装

    import Cookies from 'js-cookie'
    
    const TokenKey = 'my_token' // 需要存储token的 Cookies 前缀名称
    
    export function getToken() {
      return Cookies.get(TokenKey)
    }
    
    export function setToken(token) {
      return Cookies.set(TokenKey, token)
    }
    
    export function removeToken() {
      return Cookies.remove(TokenKey)
    }
    
    

    相关文章

      网友评论

          本文标题:2020-05-14 Vue 解决iframe跨域通信后子页面获

          本文链接:https://www.haomeiwen.com/subject/ggzanhtx.html