跨域庫herryPostMessage.js的一些優化,多iframe跨域

herry菌發表於2021-04-15

之前簡單封裝過一箇舊版,主要是開發chrome外掛時使用的。

舊庫見文章:https://www.cnblogs.com/wuhairui/p/14595893.html

 

新版庫主要做了下多個iframe和父頁面互動的優化。主要使用建構函式的方式將多個iframe的互動使用多個物件進行區分,這樣多個互動就可以互相獨立了。

並可子頁面主動呼叫傳值給父頁面。

新版程式碼:

/**
 * iframeId iframe的id
 * parentName 父視窗名,一般不改
 * childName 子視窗名 多個iframe時需要使用
 * postMessage 父視窗呼叫 需要子頁面載入完成後才能執行到
 * returnData 子視窗主動回應
 * callback 父視窗呼叫後子視窗判斷
 */
(function (w) {
  function HerryPostMessage(iframeId = 'iframe') {
    this.iframeId = iframeId;
    this.parentName = '父視窗';
    this.childName = '子視窗';
    //跨域物件
    this.messageObj = {};

    /**
     * 監聽父頁面傳送的資料
     */
    w.addEventListener(
      "message",
      async (event) => {
        const { data } = event;
        if (data && typeof data === "object" && data.name === this.parentName) {
          if (this.callback) {
            this.callback(data)
          }
        }
      },
      false
    );

    /**
     * 監聽子頁面返回的資料
     */
    w.addEventListener(
      "message",
      (event) => {
        const { data } = event;
        if (data && typeof data === "object" && data.name === this.childName) {
          if(this.messageObj[data.action]) {
            this.messageObj[data.action](data);
          }
        }
      },
      false
    );
  }

  //父頁面
  /**
   * 傳送給子頁面資料
   */
  HerryPostMessage.prototype.postMessage = function(data, fn = null) {
    const iframe = document.getElementById(this.iframeId)
    iframe.contentWindow.postMessage(
      {
        name: this.parentName, //父頁面名字
        ...data,
      },
      "*"
    );
    this.messageObj[data.action] = fn;
  };

  //子頁面
  /**
   * 返回資料給父頁面 參1=當前action 參2=返回的資料
   */
  HerryPostMessage.prototype.returnData = function(action, data) {
    top.postMessage(
      {
        name: this.childName, //子頁面名字
        action,
        data,
      },
      "*"
    );
  };

  //丟擲
  w.HerryPostMessage = HerryPostMessage;
})(window);

 

使用方法:

父子頁面均引入herryPostMessage.js。

父頁面:

引入子頁面b1,設定一個id

<iframe id="b1" src="//localhost:8081/b1.html" frameborder="0"></iframe>

建立物件,引數傳參為iframe的id,設定物件的childName也同名。

父子頁面均載入後,呼叫物件的postMessage方法,傳入action,data可傳可不傳。第二個引數為子頁面的回撥。

const b1 = new HerryPostMessage('b1')
b1.childName = 'b1';
//此處需要延遲 因為到登入子頁面載入完畢
setTimeout(() => {
    b1.postMessage({action:'geta',data: '父頁面傳給子頁面的資料'},(res) => {
        console.log('父頁面列印',res.data)
    })
},500)

子頁面:

建立該頁面的物件(一般和父頁面建立的同名)

建立callback函式,做判斷,父頁面呼叫後,會進入到這裡。處理後可以使用物件的returnData方法將資料傳回給父頁面的回撥函式中。

const b1 = new HerryPostMessage('b1');
b1.childName = 'b1';
b1.callback = (data) => {
    if(data.action === 'geta') {
        //獲取到父頁面傳來的資料
        console.log('子頁面列印',data.data)
        //子頁面回傳給父頁面資料
        b1.returnData('geta','子頁面回傳給父頁面資料')
    }
}

另外,在子頁面中直接呼叫returnData也可以主動傳回給父頁面資料

setTimeout(() => {
    b1.returnData('geta','子頁面主動傳給父頁面資料')
},1000)

效果:

 

相關文章