Window.matchmedia 监听器触发两次

Window.matchmedia listener firing twice

我正在尝试编写一些 javascript,它将在某些浏览器断点处更改 JS 配置对象中保存的一些值。

我已将 window.matchmedia 测试存储在配置对象中,然后循环遍历该对象的键以向每个测试添加一个事件侦听器,如下所示:

Object.keys(config.mediaQueries).map((key) =>{
     config.mediaQueries[key].addListener(function(){
         console.log("breakpoint change");
     });
});

https://codepen.io/decodedcreative/pen/YQpNVO

然而,当浏览器调整大小时,这些侦听器回调函数 运行,它们会出现 运行 两次。在控制台打开的情况下检查上面的 CodePen,您就会明白我的意思。

有谁知道我在这里做错了什么?

似乎事件在调整大小之前和调整大小之后触发。如果要在更改后立即记录 "breakpoint" 更改,请添加 if 语句。

编辑:Noah Freitas 关于调整大小时触发 2 个键的事件可能是正确的。如果它与密钥匹配,仍然 e.matches returns 正确,因此它应该可以正常工作

    function(e) {
      if(e.matches) {
        console.log("breakpoint change");
      }
    }

如果您将 console.log("breakpoint change"); 更改为 console.log(key, "breakpoint change");,您会看到当您手动调整浏览器大小时 xss 查询都会被触发 window.

如果您只希望回调在一段时间内触发一次 window,您需要限制事件或以其他方式实现行为。

编辑:Tomasz Bubała and Brett DeWoody 的回答都指向 event.matches 属性 作为此问题的正确且更 .matchMedia 具体的解决方案。

不确定,这是否已经是完整答案。但你是对的。回调触发两次 - 针对两个不同的键。

我修改了你的例子,所以它输出 key:

Object.keys(config.mediaQueries).map((key) =>{
    console.log("register key: '" + key + "'");
    config.mediaQueries[key].addListener(function(){
        console.log("breakpoint change key:'" + key + "'");
    });
});

生成的日志记录输出总是产生两行:

breakpoint change key:'m'
breakpoint change key:'l'

或减小宽度:

breakpoint change key:'s'
breakpoint change key:'m'

回答你的直接问题,你没有做错任何事。 JS 正在做它应该做的事情。

trld 触发了 2 个事件,但只有一个包含匹配的媒体查询。

发生的事情是,当浏览器遇到断点时,会记录 2 个事件。例如,让我们考虑将浏览器的大小从 1250 像素调整为 1150 像素的情况。当 window 的宽度达到 1199px 时,您的函数:

Object.keys(config.mediaQueries).map((key) =>{
  config.mediaQueries[key].addListener(function(event){
    console.log("breakpoint change");
  });
});

将记录 2 个事件。如果您深入研究并记录事件:

Object.keys(config.mediaQueries).map((key) =>{
  config.mediaQueries[key].addListener(function(event){
    console.log(event);
  });
});

您将看到有关媒体查询的更多信息。我已将事件对象归结为以下重要道具。

// First event
matches: true
media: "(max-width: 1199px) and (min-width: 992px)"

// Second event
matches: false
media: "(min-width: 1200px)"

这里发生的事情是记录了 2 个事件,但只有一个事件包含匹配的查询。

因此,如果我们想改进您的日志记录脚本,您可以查看 matches 属性:

Object.keys(config.mediaQueries).map((key) =>{
  config.mediaQueries[key].addListener(function(event){
    if (event.matches) { 
      console.log(event);
    }
  });
});

通过这个小改动,只会记录匹配的媒体查询。