【问题标题】:window.postMessage between iframe and its parent with Angular: does anyone have a working example?iframe 与其父级与 Angular 之间的 window.postMessage:有人有工作示例吗?
【发布时间】:2014-07-28 02:22:12
【问题描述】:

有没有人有一个工作示例来说明如何以角度发送和接收 window.postMessage() 调用?我在 github 和 ngmodules 上找到了 ng-post-message 模块,但我查看了该代码,它对我来说没有多大意义,并且文档缺少一个工作示例。

编辑:添加我失败的尝试

景色

<div simulation-host element="thing in things"></div>
</div>
<div id="debugConsole">
    <h1>MESSAGE CONSOLE</h1>
    <p id="debugText"></p>
</div>

型号

$scope.things = 
[
    {
        "location"  :   "Foobar",   
        "resource"  :   $sce.trustAsResourceUrl("http://external.domain:14168/Foo/Bar"), 
        "title"     :   "Launch"    
    }
];

我对指令的尝试

var simulationFrameHost = angular.module('proxy.directives', []);
simulationFrameHost.config(function ($sceDelegateProvider){
    //URL Regex provided by Microsoft Patterns & Practices.
    $sceDelegateProvider.resourceUrlWhitelist(['^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?$','self']);
});

simulationFrameHost.directive('simulationHost', ['$window',function($window) {
    return {
        retrict: 'ACE',
        transclude: 'element',
        replace: true,
        scope: true,
        template: [
            '<ul>',
                '<li>',
                    '<span>',
                        '<a href="#">',
                            '{{thing.location}}',
                        '</a>',
                    '</span>',
                    '<messenger>',
                        '<iframe ng-src="{{thing.resource}}"  />',
                    '</messenger>',
                '</li>',
            '</ul>'
        ].join(''),
        compile: function (tElement, tAttrs, transclude) {
            var interval;            

            var show = function(msg)
            {
                var debugText = document.getElementById("debugText");
                if(debugText){
                    debugText.innerHTML += msg + "<br/>";
                }
            };
            var rpt = document.createAttribute('ng-repeat');
            rpt.value = tAttrs.element;
            console.log(tAttrs.element);
            tElement[0].children[0].attributes.setNamedItem(rpt);

            $(tElement[0].children[0].children[0].children[0]).on("click", function(event){

                console.log(event);
                var iframe = tElement[0].children[0].children[1].children[0].contentWindow;
                show("Initiating connection with: " + event.currentTarget.host);
                var message = {
                    action: 'syn',
                    param: 'connection'
                };

                interval = setInterval(function(){

                    //*****************************************
                    iframe.postMessage(JSON.stringify(message), 'http://'+ event.currentTarget.host);
                    //*****************************************

                }, 500);
                return false;               
            });



        }
    }
}]);

我正在尝试适应 Angular 的工作遗留代码

请注意,此代码使用弹出窗口而不是 iframe;遇到了IE在windows之间的postMessage被破坏所以不得不回退到iframe的复杂情况。

标记

<body>
        <div id="debugConsole">
            <h1>MESSAGE CONSOLE</h1>
            <p id="debugText"></p>
        </div>
        <h1>This is a test</h1>

        <ul>
            <li>
                <a href= "http://external.domain:14168/Foo/Bar" target="_blank" ><p>Foobar</p></a>
            </li>
        </ul>
        <script src="js/jquery-1.10.2.min.js"></script> 
        <script src="bower_components/angular/angular.js"></script>
        <script src="bower_components/angular-animate/angular-animate.js"></script>
        <script src="bower_components/angular-route/angular-route.js"></script>
        <script src="bower_components/angular-resource/angular-resource.js"></script>
        <script src="js/SCORM_API_wrapper.js"></script>
        <script src="js/json2.js"></script>
        <script src="js/plugins.js"></script>
        <script src="js/index.js"></script>
    </body>

index.js

$('a').on("click",function(event){
    console.log(event);
    var pop = window.open(event.currentTarget.href, 'poop');
    show("Initiating connection with: " + event.currentTarget.host);
    var message = {
        action: 'syn',
        param: 'connection',
    };

    interval = setInterval(function(){
        pop.postMessage(JSON.stringify(message), 'http://'+ event.currentTarget.host);
    }, 500);
    return false;

});

$(window).on("message", function(e) {
    clearInterval(interval);

    var eventData = JSON.parse(e.originalEvent.data);
    show("Message received from: " + e.originalEvent.origin);
    if(eventData.action) {
        switch (eventData.action) {
            case 'syn-ack':
                ack(e.originalEvent, eventData.param, eventData.value);
                break;
            case "set":
                show("Set request received: " + e.originalEvent.data);
                set(eventData.param, eventData.value);
                break;
            case "get":
                show("Get request received: " + e.originalEvent.data);
                var value = get(eventData.param);
                var response = {
                    action: "response",
                    type: "get",
                    param: eventData.param,
                    value: value
                };
                e.originalEvent.source.postMessage(JSON.stringify(response), channel);
                break;
        }
    }
});

在我的指令编译中,我试图将点击事件连接到生成的锚标记。我试图点击向 iframe 发布消息,但 iframe.postMessage 什么也没做。它刚刚进入下界,我从今天早上 10 点开始就一直在研究这个。我的眼睛开始发呆:p

编辑:为单独容器之间的通用消息传递指令添加扩展要求(现在我有功能代码),无论容器类型如何:

1)iframe to parent

2)window to window

我有遗留代码工作,通过生成窗口来执行窗口到窗口消息传递 第二个在创建后立即向其发布“syn”消息。然后第二个窗口将消息作为“syn”接收,并将发送者存储为 messageHandle,以便它可以维护一个通道来发布返回消息,然后返回“syn-ack”。发起者随后发出“ack”,辅助窗口收到 ack 并继续其工作。 (如果 ack 在超时之前没有返回,我记录了连接失败,然后辅助窗口轮询一段时间以尝试恢复连接)

【问题讨论】:

  • 您能否发布您尝试过的代码示例,或者您尝试在 Angular 中模拟的等效纯 js 代码?
  • 很难重构我当前的代码以仅隔离发布消息的尝试。不过我可以试试。
  • 我作弊了。 $(window).on("消息",function(){});在控制器中。我花了太多时间试图让它以“角度方式”工作。花了大约 10 分钟让它以“实用的方式”工作。有时间我会重构。
  • 实用作品。来吧,把它作为你的答案发布。

标签: angularjs postmessage


【解决方案1】:

刚刚看到这篇文章,这可能会对你有所帮助。

(function() {
    'use strict';

    angular
    .module('postmessage')
    .factory('iFrameMessagingService', iFrameMessagingService);

iFrameMessagingService.$inject = ['$window', '$location', '$rootScope', '$log'];

function iFrameMessagingService($window, $location, $rootScope, $log) {
    var service = {
        sendMessage : sendMessage
    };

    activate();
    return service;

    function activate(){
        activateIncomingMessageHandler();
    }

    function activateIncomingMessageHandler(){
        $window.addEventListener('message', function(event){
            if (typeof(event.data) !== 'undefined'){

               // handle message
            }
        });

    }

    function sendMessage(message){
        // Dispatch the event.
        $log.debug(message);
        if($window.parent !== $window){
            $window.parent.postMessage(message, '*');
        }
    }

}
})();

【讨论】:

    【解决方案2】:

    我无法使用 Angular 指令来实现这一点。我浪费了一整晚试图“以正确的方式”完成这件事,并希望我早点放弃这个想法,因为我的要求并不真正保证它。这个东西不必扩展,因为它是专门构建的软件,用于在 X-Domain 系统之间提供消息代理。

    'use strict'
    var app = angular.module('domain.system.controllers', ['services.proxy.mine']);
    app.controller('ProxyCtrl', ['$scope', '$routeParams', '$window', '$sce', 'MyService',
                    function    ( $scope,   $routeParams,   $window,   $sce,   MyService)
                   {
                        $($window).on("message", function(e){
                           var message = JSON.parse(e.originalEvent.data);
                           if(message.recipient){
                                switch(message.recipient){
                                    case: "ProxyCtrl":
                                           //handle message;
                                           break;
                                }
                           }
                        }
                  }
    ]);
    

    我对如何将此代码转换为功能指令的详细说明 100% 感兴趣。

    【讨论】:

    • +1 这个!在不情愿地回到 jQuery 之前,我自己花了大约 3 个小时来尝试 angular 指令。如果有人能告诉我们我们缺少什么,同样会感兴趣。
    • 我很久以前写过这个问题。我没有必要重新审视这一点,但我在指令方面已经变得更好了。下次我在我的一个 Angular 客户端中工作时,我会试着找几分钟时间看看我是否可以把一些东西放在一起,可能会对你有所帮助。
    • 你能不能把$($window)换成angular.element($window)
    • 别忘了删除$scope.$on("$destroy", ...)中的监听器
    猜你喜欢
    • 2016-07-08
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 2016-03-16
    • 2020-10-09
    • 2023-03-31
    相关资源
    最近更新 更多