更新:( 回顾,小提琴和赏金)
这个问题没有引起太多关注,所以我打算花一些时间来解决这个问题。我知道我的回答和问题往往过于冗长。这就是为什么我继续设置这个 fiddle的原因,在我看来,这是我目前必须用来接近冒泡change
事件的那种代码的体面表示。我试图解决的几个问题:
- 该
pseudo-change
事件不会在选择元素上触发,除非它失去焦点。在某些情况下,应在选择新值时重定向客户端。我如何实现这一目标? - 单击标签时以及复选框本身都会调用处理程序。这本身就是您所期望的,但是由于事件冒泡,(AFAIK)无法确定单击了哪个元素。IE 的事件对象没有
realTarget
属性。 - 通过单击标签更改
checked
IE 中复选框的状态时,一切都很好(尽管它需要一些讨厌的解决方法),但是当直接单击复选框时,将调用处理程序,但选中状态保持不变,直到我单击第二次。然后值会发生变化,但不会调用处理程序。 - 当我切换到不同的选项卡并再次返回时,处理程序会被多次调用。如果选中状态实际改变了三次,如果我只直接单击一次复选框,则两次。
任何可以帮助我解决上述一个或多个问题的信息将不胜感激。拜托,我没有忘记添加一个jQuery标签,我喜欢纯JS,所以我正在寻找一个纯JS的答案。
我有一个网页,上面有超过 250 个选择元素和 20~30 个复选框。我还必须跟踪用户的行为,并采取适当的行动。因此,我很自然地委派更改事件,而不是添加数百个听众,恕我直言。
当然,IE - 公司政策:必须支持 IE8 - 在我需要时不会触发 onchange 事件。所以我试图伪造一个 onchange 事件。到目前为止,除了一件真正让我烦恼的事情之外,我的工作还算不错。
我正在使用onfocusin
并onfocusout
注册事件。在某些情况下,当用户从 a select 元素中选择一个新值时,脚本应该立即响应。但是,只要选择没有失去焦点,就不会发生这种情况。
到目前为止,这是我想出的:
i = document.getElementById('content');
if (!i.addEventListener)
{
i.attachEvent('onfocusin',(function(self)
{
return function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
switch (target.tagName.toLowerCase())
{
case 'input':
if (target.getAttribute('type') !== 'checkbox')
{
return true;
}
return changeDelegator.apply(self,[e]);//(as is
case 'select':
self.attachEvent('onfocusout',(function(self,current)
{
return function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
if (target !== current)
{
return;
}
self.detachEvent('onfocusout',arguments.callee);//(remove closure
return changeDelegator.apply(self,[e]);
}
})(self,target));
default: return;
}
}
})(i));//(fake change event, buggy
}
else
{//(to put things into perspective: all major browsers:
i.addEventListener('change',changeDelegator,false);
}
我尝试在onfocusin
处理程序中附加另一个事件侦听器,绑定到onclick
事件。它触发了onfocusout
任何选择具有焦点 ATM 的事件。唯一的问题是,99.9% 的用户会点击选择,因此该focusin
事件也会触发 onclick。
为了解决这个问题,我创建了闭包,并将当前的焦点选择及其原始值作为参数传递给它。但是有些用户确实使用他们的键盘,这些用户经常在不更改值的情况下跳到下一个选择框。每次绑定一个新的 onclick 侦听器...我确实相信有一种比检查 alle.type
并分别处理它们更简单的方法。
举个例子:带有额外onclick
监听器的代码:所有代码都与第一个片段相同,所以我只是粘贴case 'select':
块
case 'select':
self.attachEvent('onfocusout',(function(self,current)
{
return function(e)
{
e = e || window.event;//(IE...
var target = e.target || e.srcElement;
if (!(target === current))
{
return;
}
self.detachEvent('onfocusout',arguments.callee);//(remove closure
return changeDelegator.apply(self,[e]);
};
})(self,target));
self.attachEvent('onclick',(function(self,current,oldVal)
{
return function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
if (target.tagName.toLowerCase() === 'option')
{
while(target.tagName.toLowerCase() !== 'select')
{
target = target.parentNode;
}
}
if (target !== current)
{//focus lost, onfocusout triggered anyway:
self.detachEvent('onclick',arguments.callee);
return;
}
var val = target.options[target.selectedIndex].innerHTML;//works best in all browsers
if (oldVal !== target.options[target.selectedIndex].innerHTML)
{
self.detachEvent('onclick',arguments.callee);
return target.fireEvent('onfocusout');
}
};
})(self,target,target.options[target.selectedIndex].innerHTML));
default: return;