封裝一個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(父頁面)發起請求還是比較麻煩。歡迎各位提出意見或建議。