实现跨域的项目实践

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 &amp; 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);
           }
    },

 

posted on 2019-03-14 10:40  清水伊梦  阅读(258)  评论(0编辑  收藏  举报