【问题标题】:Removing a window event listener in Template.onDestroyed删除 Template.onDestroyed 中的窗口事件侦听器
【发布时间】:2016-02-04 05:19:39
【问题描述】:

我有两个模板,每个模板都包含一个 Vimeo iframe 播放器。我正在使用 FlowRouter 通过主布局上的{{> Template.dynamic template=main}} 呈现模板。

在这两个模板中,我在 onCreated 中添加了视频事件的侦听器

Template.view.onCreated( function() {
    var self = this;

    if (window.addEventListener) {
        window.addEventListener('message', function(event) {
            viewMessageReceived(event, self)}, false);
    } else {
        window.attachEvent('onmessage', function(event){
            viewMessageReceived(event, self)}, false);
    }
});

并在onDestroyed 中销毁它们

Template.view.onDestroyed( function() {
    if (window.removeEventListener) {
        console.log('view remove');
        window.removeEventListener('message', function(event) {
            viewMessageReceived(event, self)}, false);
    } else {
        window.detachEvent('onmessage', function(event){
            viewMessageReceived(event, self)}, false);
    }
});

这是匿名事件处理程序调用的函数:

function viewMessageReceived(event, self) {
// Handle messages from the vimeo player only
    if (!(/^https?:\/\/player.vimeo.com/).test(event.origin)) {
        return false;
    }

    if (self.playerOrigin === '*') {
        self.playerOrigin = event.origin;
    }

    var data = JSON.parse(event.data);

    switch (data.event) {
        case "ready":
            initializePlayer(self);
            break;
        case "playProgress":
            self.playerTime.set(data.data.seconds);
            if (self.duration === '*') self.duration = data.data.duration;
            break;
        case "play":
            self.playerStatus.set("playing");
            break;
        case "pause":
            self.playerStatus.set("paused");
            break;
    }
}

当我切换到不同的模板时,onDestroyed 运行并且我的console.log('view remove') 触发,正如预期的那样。

但是,当我导航到使用视频播放器加载另一个模板的页面时,previous 视频模板中的事件处理程序会收到一个 Vimeo“playProgress”message,应该是不久前被删除的。这会引发错误,因为之前的模板已被销毁。

Uncaught TypeError: Cannot read property 'contentWindow' of undefined

来自这个函数的最后一行:

function post(template, action, value) {
    console.log('view action: %s value: %s', action, value);
    var data = {method: action};
    if (value) data.value = value;
    var message = JSON.stringify(data);
    template.player[0].contentWindow.postMessage(message, template.playerOrigin);
}

每个包含视频的模板都有自己的 .js 文件,因此它们都有自己的 post 函数声明。我的理解是定义一个函数,该函数的范围仅限于页面。

只有一条消息发给了错误的玩家。之后,它们到达当前加载的播放器。

为什么在我已经销毁模板以及移动到另一个播放器之后,Vimeo 消息事件会到达或得到处理?

【问题讨论】:

    标签: meteor vimeo-api flow-router


    【解决方案1】:

    W3Schools 网站上关于removeEventListener() 方法的引用:

    // Attach an event handler to <div>
    document.getElementById("myDIV").addEventListener("mousemove", myFunction);
    
    // Remove the event handler from <div>
    document.getElementById("myDIV").removeEventListener("mousemove", myFunction);
    

    注意:要删除事件处理程序,使用 addEventListener() 方法必须是一个外部函数,就像在 上面的示例 (myFunction)。

    匿名函数,例如 "element.removeEventListener("event", function(){ myScript });" 不起作用。

    为此,您需要将函数定义移到onRenderedonDestroyed 事件之外的某个位置,并在添加/删除事件侦听器中传递函数名称。

    【讨论】:

    • 我原来是这样的,但还是有同样的问题。
    • 我在您的代码中没有看到您调用post 函数的地方?了解如何调用该函数会很有帮助。 Vimeo 播放器本身是否以某种方式被破坏?即使事件侦听器已从第一个模板中删除,播放器的工件仍可能在 DOM 和/或内存中徘徊。当第二个模板加载时,它可能会从第一个模板的播放器实例重新加载数据,因为全局变量不会在页面路由之间的 Meteor 中被清除。
    • post 在页面上的任何内容想要与播放器交互时被调用。在这个地方,它被 intializePlayer 函数调用,没有看到。不过,你的回答是正确的。虽然我将一个外部函数附加到 EventListener,但我定义了 Template.onCreatedinside 函数,这意味着 Template.onDestroyed 无权访问它。解决方案是在顶层var viewMessageReceived = function(event) { } 中声明一个空函数,然后在Template.onCreated 中重新定义该函数,我可以通过this 访问模板。
    猜你喜欢
    • 2015-12-26
    • 1970-01-01
    • 2018-09-04
    • 2022-11-04
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    • 2012-03-31
    • 2011-10-27
    相关资源
    最近更新 更多