更新:( 回顾,小提琴和赏金)
这个问题没有得到太多关注,所以我打算花一些时间在上面。我知道我的回答和问题都过于冗长。这就是我继续设置这个 fiddle的原因,在我看来,这是我目前必须用来接近冒泡change
事件的那种代码的体面表示。我试图解决的几个问题:
- 该
pseudo-change
事件不会在选择元素上触发,除非它失去焦点。在某些情况下,应在选择新值时重定向客户端。我如何实现这一目标? - 单击标签以及复选框本身时都会调用处理程序。这本身就是您所期望的,但是由于事件冒泡,(AFAIK)无法确定单击了哪个元素。IE 的事件对象没有
realTarget
属性。 - 当
checked
通过单击标签更改IE 中复选框的-state 时,一切正常(尽管它需要一些讨厌的解决方法),但是当直接单击复选框时,会调用处理程序,但选中状态保持不变,直到我单击第二次。然后值会更改,但不会调用处理程序。 - 当我切换到不同的选项卡并再次返回时,处理程序被多次调用。如果选中状态实际改变了三次,如果我只直接单击复选框一次,则两次。
任何可以帮助我解决上述一个或多个问题的信息将不胜感激。拜托,我没有忘记添加一个jQuery标签,我喜欢纯JS,所以我正在寻找一个纯JS的答案。
我有一个网页,上面有超过 250 个选择元素和 20~30 个复选框。我还必须跟踪用户的行为,并采取适当的行动。因此,我很自然地委托更改事件,而不是添加数百个听众,恕我直言。
当然,IE - 公司政策:必须支持 IE8 - 在我需要时不会触发 onchange 事件。所以我试图伪造一个 onchange 事件。到目前为止,除了一件真正让我感到烦恼的事情之外,我所拥有的工作还算不错。
我正在使用onfocusin
和onfocusout
注册事件。在某些情况下,当用户从 a select 元素中选择一个新值时,脚本应该立即响应。但是,只要 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。
为了解决这个问题,我创建了闭包,并将当前的 select-in-focus 和它的原始值作为参数传递给它。但是有些用户确实使用他们的键盘,这些用户通常在不更改值的情况下跳到下一个选择框。每次绑定一个新的onclick听众......我相信有HAS比检查所有更简单的方法e.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;