簡介
一個利用html5的跨域api postMessage解決一個系統中,多個iframe跨域通信交互的js庫。
github地址 :cross-domain
背景
最初公司只有一個系統來做銷售,隨着公司業務越來越多,搭建很多類似的系統(這些系統本來是沒有任何關係的,每個系統目前都非常複雜)。
由於目前公司戰略有調整,原來的銷售是針對某種產品,現在銷售工作要針對客户進行多產品的銷售促成,這樣一個銷售人員就需要打開各種系統進行業務操作,非常不方便,而且銷售數據間不能有效傳遞,所就需要把各個不相關的系統整合在一起,實現跨業務線銷售和數據共享。若將這想要將這些複雜系統整合在一起,無論是從人力物力上都是不太可能接受的。
所以選擇了使用iframe將各系統嵌入一個框架系統,各系統從物理上還是分開不變,而從邏輯上(從用户角度看就是一個系統)看起來是一個系統。
然而各系統採用了不同的域名,與主框架系統和其它業務系統有跨域問題(若將所有域名改為同一域名下可能會產生一些系統間頁面元素和樣式的衝突)
故採用了HTML5標準下的postMessage來解決該問題。
介紹
- 示意圖
- http://a.com 是最外層主系統的頁面,為master
- http://b.com 和 http://c.com 為被嵌入的子系統slave,當然也可以嵌入N個子系統
master和slave都是有各自的域名,由於瀏覽器的安全限定,兩個iframe正常是不能進行數據交換和api調用的。當然有一些特殊方法如jsonp,iframe name等。如果想了解,可以看看我的另一篇文章jsonp實現原理 。
在HTML5中新增了postMessage方法,postMessage可以實現跨文檔消息傳輸(Cross Document Messaging),Internet Explorer 8, Firefox 3, Opera 9, Chrome 3和 Safari 4都支持postMessage。postMessage api詳細介紹,請查看 postMessage
示意圖如下:
https://raw.githubusercontent...
提供的主要API
js庫提供了簡潔的調用和提供接口的方法,介紹如下
- 接口調用(向其它iframe發送數據)
/**
* 發送消息方法
* @param {String} componentName組件名稱
* @param {String} method接口名稱(對方通過API extends提供的接口名)
* @param {Object} data數據
* @param {Function} callback回調
*/
send : function(componentName,method,data,callback,type);
- 提供接口(提供前端接口,可供其它iframe調用)
/**
* 擴展接口方法,供調用方send方法調用
* @param {String} name接口名稱
* @param {Function} fun 接口方法
*/
extends : function(name,fun);
例子
- Master代碼如下
啓動http服務,http://localhost/cross-domain...
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!--引入js庫-->
<script type="text/javascript" src="../src/cross-domain.js"></script>
</head>
<body>
Test Page MASTER
<button onclick="sendMesg1()">send data to Slave1</button>
<button onclick="sendMesg2()">send data to Slave2</button>
<br/>
<!--slave1-->
<iframe src="http://127.0.0.1/cross-domain/example/slave1.html" name="SLAVE1" id="SLAVE1"></iframe>
<!--slave2-->
<iframe src="http://127.0.0.1/cross-domain/example/slave2.html" name="SLAVE2" id="SLAVE2"></iframe>
<div id="content"></div>
</body>
<script type="text/javascript">
var me = CD.component.name;
function genInfo(name){
return {info : "Hello [" + name + "] , I am [" + me + "] Now at " + new Date()};
}
//調用SLAVE2的changeSlave1前端接口,接口參數為genInfo("SLAVE1")
function sendMesg1 (argument) {
CD.send("SLAVE1" , "changeSlave1" ,genInfo("SLAVE1") ,function(data){
console.log("callback fire");
writeHtml(data);
});
}
//調用SLAVE2的changeSlave2前端接口,接口參數為genInfo("SLAVE2")
function sendMesg2 (argument) {
CD.send("SLAVE2" , "changeSlave2" , genInfo("SLAVE2"));
}
//MASTER提供接口,可供SLAVE1和SLAVE2調用
CD.extends("changeMaster" , function(data){
writeHtml(data.info);
});
//當SLAVE1和SLAVE2調用changeMaster接口時,會打印在MASTER的頁面中
function writeHtml(text){
var content = document.getElementById("content");
content.innerHTML += "<br/>" + text;
}
console.log(CD);
</script>
</html>
- Slave1
啓動http服務,http://127.0.0.1/cross-domain...
<!DOCTYPE html>
<html>
<head>
<title>slave1</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="../src/cross-domain.js"></script>
</head>
<body>
<div id="main">
I am salve1 frame
<button onclick="sendMesg()">send data</button>
</div>
<div id="content"></div>
</body>
<script type="text/javascript">
var me = CD.component.name;
function genInfo(name){
return {info : "Hello [" + name + "] , I am [" + me + "] Now at " + new Date()};
}
//調用MASTER的changeMaster接口,數據為genInfo("MESTER")
function sendMesg (argument) {
CD.send("MESTER" , "changeMaster" ,genInfo("MESTER"));
}
//提供前端接口changeSlave1,可供MASTER和其它SLAVE調用
CD.extends("changeSlave1" , function(data){
writeHtml(data.info);
return "Slave1 changeSlave1 is called";
});
function writeHtml(text){
var content = document.getElementById("content");
content.innerHTML += "<br/>" + text;
}
console.log(CD);
</script>
</html>
- Slave2
啓動http服務,http://127.0.0.1/cross-domain...
<!DOCTYPE html>
<html>
<head>
<title>slave2</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="../src/cross-domain.js"></script>
</head>
<body>
<div id="main">
I am slave2 frame
<button onclick="sendMesg()">send data</button>
</div>
<div id="content"></div>
</body>
<script type="text/javascript">
var me = CD.component.name;
function genInfo(name){
return {info : "Hello [" + name + "] , I am [" + me + "] Now at " + new Date()};
}
//調用MASTER的changeMaster接口,數據為genInfo("MESTER")
function sendMesg (argument) {
CD.send("MESTER" , "changeMaster" ,genInfo("MESTER"));
}
//提供前端接口changeSlave2,可供MASTER和其它SLAVE調用
CD.extends("changeSlave2" , function(data){
writeHtml(data.info);
});
function writeHtml(text){
var content = document.getElementById("content");
content.innerHTML += "<br/>" + text;
}
console.log(CD);
</script>
</html>
- 交互效果
應用案例
某企業作業系統