实现跨域的项目实践
1.功能描述:
实现在系统主窗口点击 “Export to excel” link,open一个新的窗口提示用户‘下载即将开始,正在下载’字样, 同时“Export to excel” link 灰显, 当新窗口下载完成后,提示下载成功或失败信息,同时主窗口的 “Export to excel” link 恢复正常,即可再次点击下载。
2.主要技术:
(1)html5的postMessage 实现两个跨域的通信,下载完成的通知
(2)用动态加载 <script> 标签引入require.js , 指定data-main 程序的主模块,引入主域的公共库文件,方法等
3.实现过程:
Main 窗口:
exportReportToExcel:function (e){ … var baseUrl = window.location.host; var protocol = window.location.protocol; var href = protocol + "//" + baseUrl; window.open(href+"/exportReportToExcel.html?"+reportId); //打开新的子窗口 }

Son 窗口:
<!Doctype html>
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link rel="stylesheet" type="text/css" href="/styles.css?x.x.x.css"/>
<link type="text/css" rel="stylesheet" href="/exportStyle.css"/>
<title>ACTIVE Works Camp & Class Manager</title>
<script type="text/javascript">
var reportId = document.location.href.split("?")[1].split('&')[0]; //通过get方式先获取到reportId
window.onbeforeunload =function() { //在即将离开当前页面(刷新或关闭)时执行,广发postMessage,内容就是这个reportId
window.opener.postMessage(reportId,'*');
};
</script>
</head>
<body>
<header id="globalHeader" class="show-html">
<nav id="topNav">
<img src="/static/images/camps/CampsLogo.png">
</nav>
</header>
<div class="downloadPrompt">
<p>Your Report is being generated. Please do not close this window.</p><br/>
<p>Download will begin automatically as soon as your report has been generated.</p>
<br/><br/>
<div id="loadMessage" style="color:red;font-size:12px;"></div>
</div>
<!— 下面这块是实现一个失败时提示一个弹出框的特效 (遮罩,弹出框 ) —>
<div id="bg"></div>
<div class="promPit" id="promPit">
<div class="prompt">
<div class="title">
Could not download report
<span class="closeIcon" onclick="closePrompt()">X</span>
</div>
<div class="content" id="content">Sorry, there was a problem trying to download your report. Please try again and contact technical support if the problem persists.</div>
<div class="okbutton" onclick="closePrompt()">OK</div>
</div>
</div>
<script>
window.onload = function(){
closePrompt();
var newtimestamp = Date.parse(new Date());
var timestamp=document.location.href.split("?")[1].split('&')[1];
var d = (newtimestamp - timestamp)/1000;
//when the time more than 5s, the href will failture.
if(d > 30){
showPrompt('The link have grown stale. Please try again and contact technical support if the problem persists.');
return;
}else{
document.getElementById('loadMessage').innerHTML = "";
var oBody = document.getElementsByTagName('body').item(0);
var oScript= document.createElement("script");
oScript.type = "text/javascript";
oScript.src="/arch/requirejs/require.js";
oScript.setAttribute('data-main','exportToExcelMain.js')
//这里也关键,引入require.js, 并通过data-main属性,指定网页程序的主模块,这样主模块的一些组件就可以直接require进来使用
oBody.appendChild(oScript);
}
}
function closePrompt(){
document.getElementById('promPit').style.display = "none";
document.getElementById('bg').style.display = "none";
}
function showPrompt(str){
if(str){
document.getElementById('content').innerHTML = str;
}
document.getElementById('promPit').style.display = "block";
document.getElementById('bg').style.display = "block";
}
</script>
</body>
</html>


exportToExcelMain.js 的实现:
"use strict"; require.config({ baseUrl: "./arch", waitSeconds: 180, paths: { 'underscore': 'lib/underscore', 'jquery': 'lib/jquery', 'WaitManager': '../camps/Application/WaitManager' }, shim: { 'jquery': { exports: 'jQuery' }, 'underscore': { deps: ['jquery'], exports: '_' } } }); define([ 'polling', 'jquery', 'underscore', 'WaitManager' ], //这是主域实现下载的通用方法,拿过来用就好了 function (polling, $, _, WaitManager) { var exportReport = function(reportId) { return $.ajax({ type: 'POST', url: '/service/json/aui/report/customerReport/'+reportId, contentType: 'application/json' }); }; var pollForCompleteReport = function(token) { var data = { pollForReportDto: { reportTokenDto: { value: token }, timeout: 1 } }; return $.ajax({ type:'POST', contentType: 'application/json', url:'json/ReportProxyService/pollForReportResult', data:JSON.stringify(data) }); }; var showPrompt = function(){ document.getElementById('promPit').style.display = "block"; document.getElementById('bg').style.display = "block"; }; WaitManager.startWaiting(); var reportId = document.location.href.split("?")[1].split('&')[0]; var fileId; var promise = exportReport(reportId); promise.then(function(response){ if(!response.isError){ var token = response.value; polling.start({ id:token, interval:1000, onPoll: function(onPollResult){ var promiseToken = pollForCompleteReport(token); promiseToken.then(function(pollingResult){ if(!pollingResult.isError){ fileId = pollingResult.fileId; onPollResult(!!fileId); }else{ WaitManager.stopWaiting(); window.opener.postMessage(reportId,'*'); // 关键在这里,下载失败后广发消息给主窗口,返回这个reportId showPrompt(); } }); }, onComplete: _.bind(function(){ WaitManager.stopWaiting(); window.opener.postMessage(reportId,'*'); // 关键在这里,下载成功后广发消息给主窗口,返回这个reportId downloadFinishedReport(fileId); $('#loadMessage').html('Download successful!'); }, this) }); }else { WaitManager.stopWaiting(); showPrompt(); } }); var downloadFinishedReport = function(fileId) { if (fileId.indexOf('FID=') !== -1) { window.location = '/sys/exported?' + fileId; } }; });
主窗口是怎么接收这个消息的?
看这里:
initialize: function(){ function receiveMessage(event){ console.log(event.data); $('a.exportexcel[data-id='+event.data+']').removeAttr('disabled').css('color','#008cd2').addClass('exportfinish'); //改变那条reportId 的按钮状态 } if (typeof window.addEventListener != 'undefined') { window.addEventListener('message', receiveMessage, false); //监听window的message事件,接收消息 } else if (typeof window.attachEvent != 'undefined') { //这里做了一下兼容IE //for ie window.attachEvent('onmessage', receiveMessage); } },
浙公网安备 33010602011771号