封裝一個postMessage庫,進行iframe跨域互動

herry菌發表於2021-03-30

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

相關文章