我可以在JavaScript中的事件对象上安全地设置自定义属性吗?

时间:2018-10-17 16:04:26

标签: javascript events

我想在侦听器中的click事件上设置自定义属性,然后在另一个事件侦听器中进一步读取此属性:

document.body.addEventListener('click', function(e) {
    if (e.someCustomProperty) {
        // ...
    }
});

document.getElementById('some-element').addEventListener('click', function(e) {
    e.someCustomProperty = someValue;
});

在我尝试使用的所有浏览器的最新版本中,这似乎都可以正常工作:

  • Windows:IE11,Edge,Chrome,Firefox
  • iPhone:Safari,Edge,Chrome,Firefox

冒泡时,事件对象保留自定义属性。

这使我非常有信心这种行为得到了广泛支持,但是我找不到任何证据证明这是标准行为。

我是否可以相信这种行为在所有现代浏览器中都能起作用,并且会继续起作用?

如果没有,执行此操作的标准方法是什么?


我找到了similar question from 2011,但是唯一的答案现在已经过时了,提到它不能在IE8上使用(今天我不在乎)。


背景

也许我应该为我要实现的目标提供一些背景知识,以及为什么以下提供的替代方法-我认为-不能帮助您

我有一个模式窗口,基本上是屏幕中央的固定DIV:

<body>
    <div id="modal">
        <!-- content -->
    </div>
</body>

模态打开后,我在body上设置了一个点击侦听器,它检查模态内部还是外部发生了点击:

  • 如果点击发生在模态内部,则侦听器不执行任何操作
  • 如果点击发生在模态之外,则监听器会关闭模态

因此,下面的代码:

document.body.addEventListener('click', function(e) {
    if (! e.insideModal) {
        modal.close();
    }
});

document.getElementById('modal').addEventListener('click', function(e) {
    e.insideModal = true;
});

失败的替代方法:

  • 我不能只将stopPropagation()放在模式点击侦听器中,因为body上的其他侦听器仍必须能够捕获点击;
  • 我无法在主体点击监听器中使用document.getElementById('modal').contains(e.target),因为当点击起泡到body时,模态的内容可能已经更改,并且点击目标可能消失;
  • 我无法在目标元素的window或其他任何地方使用dataset上的属性,因为我看不到如何帮助我知道 this 特定点击在到达body之前已经到达了模式;如果您愿意,可以随时鸣叫!

这就是为什么该活动看起来像是放置此信息的最佳位置。

2 个答案:

答案 0 :(得分:0)

您可以将要传递的数据存储在data-*属性中(这是它们的存在-存储自定义数据)。您可以将需要传递的数据分配给event.target.dataset.someCustomProperty并在下一个处理程序中读取它。这种解决方案的缺点是所有数据都应转换为字符串(如果需要传递对象,则必须在其上使用JSON.stringify)。

document.getElementById('div').addEventListener('click', event => {
  console.log(event.target.dataset.customProperty);
});

document.getElementById('button').addEventListener('click', event => {
  event.target.dataset.customProperty = "Value of custom property";
});
<div id="div">
 <button id="button">Click me</button>
</div>

澄清后编辑

为了使模式窗口在外部单击时可以关闭,可以使用一种非常简单的技术:模式窗口用透明的覆盖物包裹,该覆盖物覆盖了整个屏幕,并且具有onclick事件监听器,在内部它与{{ 1}}(发出event.target事件的元素)和click(附加事件监听器的元素)。相等意味着点击了叠加层。不等于表示已点击了模式。

event.currentTarget
function openModal() {
    document.getElementById('overlay').classList.add('visible');
}

document.getElementById('overlay').addEventListener('click', event => {
    if(event.target === event.currentTarget){
       event.target.classList.remove('visible');
    }
});
.overlay {
  display: none;
  background: transparent;
  height: 100vh;
  width: 100vw;
  position: fixed;
  top: 0;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
}

.overlay.visible {
  display: flex
}

.modal {
  width: 100px;
  height: 100px;
  background: grey;
}

答案 1 :(得分:0)

我不推荐。这些是原因:

  • 未记录意味着不可靠,可能带来意外等。
  • 似乎对于任何元素的不同事件侦听器都有一个事件对象。因此,将数据分配给事件对象并不能实现很多目标。同样的结果,您可以将数据分配给window