更新:(概述、fiddle 和奖励)
这个问题没有得到太多关注,所以我要花一些声望来解决它。我知道我在回答和问题中往往过于冗长。这就是为什么我设置了这个fiddle,在我看来,它是目前我需要使用的代码的一个不错的表示。 我正在尝试解决以下几个问题:
伪更改
事件不会在选择元素上触发,除非它失去焦点。 在某些情况下,客户端应在选择新值后重定向。 我该怎么做?- 处理程序既在单击标签时被调用,也在单击复选框本身时被调用。 从本质上讲,这是您所期望的,但由于事件冒泡,不可能确定单击了哪个元素。 IE的事件对象没有
realTarget
属性。 - 在IE中通过单击标签更改复选框的
checked
-状态很顺利(尽管需要一些恶心的解决方法),但是直接单击复选框时,处理程序被调用,但是检查状态保持不变,直到我第二次单击。 然后值才改变,但处理程序没有被调用。 - 当我切换到其他选项卡,然后再切回来时,处理程序会被多次调用。 如果已经更改了选中状态,则调用三次,如果我只点击过一次 checbox,则调用两次。
任何可以帮助我解决上述一个或多个问题的信息都将不胜感激。 请注意,我没有忘记添加jQuery标签,我喜欢纯JS,因此正在寻找纯JS答案。
我有一个包含超过250个选择元素和20-30个复选框的网页。 我还必须跟踪用户的操作并采取相应措施。 因此,在我的看法中,委派更改事件而不是添加数百个侦听器是非常自然的。
当然,IE -公司策略:必须支持IE8-在我需要它时不会触发onchange事件。 因此,我正在尝试伪造onchange事件。 到目前为止,我所拥有的东西工作得相当好,除了有一件事情真的很烦人。
我使用onfocusin
和onfocusout
来注册事件。 在某些情况下,当用户从选择元素中选择新值时,脚本应立即响应。 但是,只要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
事件。唯一的问题是,99.9%的用户会点击选择器,所以focusin
事件也会触发一个onclick。
为了解决这个问题,我创建了闭包,并将当前的选择器和其原始值作为参数传递给它。但是一些用户确实使用键盘,这些用户经常切换到下一个选择框而不更改值。每次绑定一个新的onclick监听器...我确信必须有比检查所有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;
target.checked === true
,它刚刚被选中了,还是即将取消选中?无法判断。字符用完了。changeDelegator.apply(this,[e]);
),因此我认为它是实际处理程序的扩展/延续。我知道“focusin”在选项卡被_恢复_时触发,但它仅针对由委托函数处理的每个事件触发。 字符....