JavaScript:如何在internet explorer中模拟更改事件(委派)
更新:(重述、提琴和赏金) 这个问题一直没有得到太多的关注,所以我将花一些时间来讨论它。我知道我的回答和问题都过于冗长。这就是为什么我继续进行设置,在我看来,这是一种很好的代码表示形式,我目前必须使用这种代码来接近冒泡的JavaScript:如何在internet explorer中模拟更改事件(委派),javascript,internet-explorer,dom-events,event-delegation,Javascript,Internet Explorer,Dom Events,Event Delegation,更新:(重述、提琴和赏金) 这个问题一直没有得到太多的关注,所以我将花一些时间来讨论它。我知道我的回答和问题都过于冗长。这就是为什么我继续进行设置,在我看来,这是一种很好的代码表示形式,我目前必须使用这种代码来接近冒泡的change事件。我正试图解决几个问题: pseudo change事件不会在select元素上触发,除非它失去焦点。在某些情况下,应在选择新值时重定向客户端。我如何做到这一点 该处理程序在单击标签时被调用,并且复选框本身也被调用。这本身就是您所期望的,但是由于事件冒泡,因此(A
change
事件。我正试图解决几个问题:
pseudo change
事件不会在select元素上触发,除非它失去焦点。在某些情况下,应在选择新值时重定向客户端。我如何做到这一点realTarget
属性选中状态时,一切正常(尽管需要一些棘手的解决方法),但当直接单击复选框时,将调用处理程序,但选中状态保持不变,直到我再次单击为止。然后值会更改,但不会调用处理程序
我有一个网页,上面有超过250个选择元素,还有20~30个复选框。我还必须跟踪用户的行为,并采取适当的措施。因此,我很自然地授权变更事件,而不是添加数百个侦听器,IMHO 当然,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
事件。它触发了任何select有焦点的ATM的onfocusout
事件。唯一的问题是,99.9%的用户会单击一个select,因此focusin
事件也会触发onclick
为了解决这个问题,我创建了闭包,并将焦点中的当前select及其原始值作为参数传递给它。但有些用户确实使用键盘,这些用户通常在不更改值的情况下切换到下一个选择框。每次绑定新的onclick侦听器时。。。我相信一定有比检查所有e更简单的方法。键入,然后分别处理它们
举个例子:带有一个额外的onclick
listener的代码:所有代码都与第一个代码片段相同,因此我只粘贴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;
虽然我同意在整个表单上只有一个事件监听器比有多个监听器更好,每个元素一个监听器,但您必须评估您的决策的成本和收益。一个侦听器的好处是减少了内存占用。缺点是,您必须使用复杂的代码技巧来绕过浏览器错误的事件实现、增加执行时间、误用事件类型、反复注册和注销事件侦听器,这可能会给某些用户造成混乱
回到好处上来,如果您只为所有元素附加与侦听器相同的函数,那么内存占用就不会太大。内存是当前计算机所不缺少的
即使这不能回答您的问题,我还是建议您停止尝试使其工作,而是在每个表单元素上附加侦听器
要稍微说明你的观点:
你确定吗?我已经尝试过了,当我从下拉列表中单击一个选项后,IE7和IE8都会启动onchange
侦听器。它甚至在使用向上/向下键更改选择时激发
确实,您不能轻松地将标签上的事件连接到受影响的复选框,但您为什么要这样做?无论如何,change
事件都会在复选框上触发,您应该只关注该事件。但是,如果必须从标签上的事件访问复选框,则可以手动执行此操作。如果事件的目标是一个标签,那么您就知道该标签以某种方式与输入相关。根据标签的使用方式,您可以选择嵌套在标签
中的输入
元素,或者获取ID位于标签
的属性中的元素
修复复选框在更改错误时返回上一个值的一种方法是对复选框上的事件执行this.blur()
当您说“handler”时,您是指事件处理程序中的onfocusin,还是changeDelegator
?重新激活选项卡时,在
事件中看到聚焦是正常的。我不知道为什么会多次触发事件,所以我只是猜测:一个可能是活动输入接收到的焦点;第二个可能是文档本身接收到的焦点;我不知道为什么会有第三个电话。我不明白w
window.attachEvent('onload',function ieLoad()
{
var mainDiv = document.getElementById('main');//main div, from here events will be delegated
var checks = mainDiv.getElementsByTagName('input');//node list of all inputs
var checkStates = {};
for (var i=0;i<checks.length;i++)
{
if (checks[i].type === 'checkbox')
{//get their checked states on load, this object serves as a reference
checkStates[checks[i].id] = checks[i].checked;
}
}
mainDiv.attachEvent('onfocusin',(function(initState)
{//initState holds a reference to the checkStates object
return function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
//id of checkboxes used as key, so no checking for tagName or type required
if (!initState.hasOwnProperty(target.id) || target.checked === initState[target.id])
{//don't call method if checkstate is unchanged, either. I'll explain in a minute
return e;
}
initState[target.id] = target.checked;//set new checked-state
changeDelegator.apply(target,[e]);//delegate
};
})(checkStates));
window.detachEvent('onload',ieLoad);//avoid mem-leak with onload handler!
});