封装一个postMessage库,进行iframe跨域交互

这是近期个人在开发chrome插件时的其中一个小总结。还有很多没有总结出来。因为目前插件还在迭代中,(herry菌插件,用于B站C站),属于个人业余的一个小项目。还有很多功能没有实现,以及还需要再看能加上什么功能。

 

封装的postMessage库 herryPostMessage.js

(function (w) {
  //herry对象
  w.herry = {};
  //iframe的id
  if(!herry.iframeId) {
    herry.iframeId = 'iframe'
  }
  //父窗口名字
  if(!herry.parentName) {
    herry.parentName = '父窗口'
  }
  //子窗口名字
  if(!herry.childName) {
    herry.childName = '子窗口'
  }
  //跨域对象
  const messageObj = {};
  //父页面
  /**
   * 发送给子页面数据
   */
  const postMessage = (data, fn = null) => {
    const iframe = document.getElementById(herry.iframeId)
    iframe.contentWindow.postMessage(
      {
        name: herry.parentName, //父页面名字
        ...data,
      },
      "*"
    );
    messageObj[data.action] = fn;
  };
  /**
   * 监听子页面返回的数据
   */
   w.addEventListener(
    "message",
    (event) => {
      const { data } = event;
      if (data && typeof data === "object" && data.name === herry.childName) {
        messageObj[data.action](data);
      }
    },
    false
  );
  //子页面
  /**
   * 返回数据给父页面 参1=当前action 参2=返回的数据
   */
  const returnData = (action, data) => {
    top.postMessage(
      {
        name: herry.childName, //子页面名字
        action,
        data,
      },
      "*"
    );
  };
  /**
   * 监听父页面发送的数据
   */
   w.addEventListener(
    "message",
    async (event) => {
      const { data } = event;
      if (data && typeof data === "object" && data.name === herry.parentName) {
        if (herry.callback) {
          herry.callback(data)
        }
      }
    },
    false
  );
  herry.postMessage = postMessage;
  herry.returnData = returnData;
})(window);

 

使用这个库让a域名下获取b域名下的数据,即a发出请求,b返回给a数据a是父页面,b是子页面

使用:

域名a和b的页面上都需要引入herryPostMessage.js

a页面处理(父页面):

加入iframe(src是b域名的页面,需要设置一个id,一般也可以将iframe使用样式隐藏掉)。

<iframe
  src="//b.com/xxx.html"
  id="ifr"
  frameborder="0"
></iframe>

设置iframeId=上面的这个id:

herry.iframeId = "ifr";

发起请求(action是设置的一个请求名,在b页面中进行匹配用。后面的数据是携带给b页面用的参数。后面的res是b页面执行后的回调函数,可进行处理b返回的数据):

herry.postMessage({ action:'geta1', x: 1 }, (res) => {
  console.log(res.data);
});

 

b页面处理(子页面):

b页面的herry.callback通过action匹配执行,并做处理,通过herry.returnData将数据返回给a的回调函数。即实现了交互。

herry.callback = async (data) => {
  if (data.action === "geta1") {
    //...
    herry.returnData(data.action, { x: 2 });
  }
  //...
};

 

不过这种封装方式也不是特别好,有局限性,比如b(子页面)像a(父页面)发起请求还是比较麻烦。欢迎各位提出意见或建议。

posted @ 2021-03-30 11:04  herry菌  阅读(707)  评论(0编辑  收藏  举报