JavaScript的:如何模拟在Internet Explorer变化事件(代表团)JavaScr

2019-06-14 14:43发布

更新:( 回顾一下,小提琴和赏金)

这个问题还没有被得到太多的关注,所以我会花一些代表就可以了。 我知道,我往往是在我的答案和问题都过于冗长。 这就是为什么我说干就干,设立这个小提琴 ,这一点,在我看来,我目前不必使用来接近沸腾的那种代码体面的表现change事件。 一对夫妇的我试图解决的问题:

  1. pseudo-change不会触发事件上选择元素,除非它失去焦点。 在某些情况下,客户应在选择一个新的值被重定向。 如何实现这一目标?
  2. 该处理器将被调用这两个标签被点击时,以及复选框自己。 就其本身而言这是你所期望的,但由于事件冒泡它(据我所知)无法确定点击了哪个元素。 IE浏览器的事件对象不具有realTarget财产。
  3. 当改变checked通过点击标签在IE复选框的通态,一切都很好(尽管它需要一些讨厌的解决方法),而是直接点击复选框时,调用处理程序,但选中状态保持不变,直到我点击第二次。 那么该值改变,但处理不叫。
  4. 当我切换到不同的选项卡,然后再返回,处理程序被调用多次。 三次如果检查的状态实际改变,如果我两次点击checbox直接一次。

任何信息,可以帮助我解决的问题的一个或多个以上,将不胜感激。 拜托,我没有忘记添加一个jQuery的标签,我喜欢纯JS,所以我在寻找一个纯粹的JS答案。


我有一个网页,上面有超过250选择的元素,和20〜30复选框。 我也有跟踪用户的行为,并采取适当措施。 因此,它是很自然的我委托更改事件,而不是增加数百位听众,恕我直言。

当然,IE -company政策:IE8必须是当我需要它supported-不会触发onchange事件。 所以我想伪造一个onchange事件。 我迄今距1件事真让我心烦的工作还算不错。
我使用onfocusinonfocusout注册事件。 在某些情况下,当用户选择从一个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听众......我相信必须比检查所有一个简单的方法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;

Answer 1:

虽然我同意,这将是更好的只有一个整体的形式,而不是很多听众,每一个元素的事件监听器,你必须评估你的决定的成本和收益。 一个监听器的好处是减少内存占用。 缺点是,你必须做这样复杂的代码的技巧来解决一个浏览器的不正确执行的事件,增加了执行时间,误用事件类型,重复注册和取消注册事件侦听器,可能造成混乱到一些用户。

回来的好处,内存占用是没有这么大,如果你只是附上相同的功能,为所有元素的监听器。 记忆是什么,目前的电脑不缺。

即使这不回答你的问题,我建议你停止努力,使这项工作,而是附加的每个表单元素上的听众。

为了解决您的点了一下:

  1. 你确定吗? 我试图从微软的文档的基本的例子 ,而IE7和IE8都火onchange监听器后,我点击从下拉菜单中的选项。 它甚至改变与UP / DOWN键选择当火灾。

  2. 虽然这是真的,你不能轻易的标签上连接一个事件到受影响的复选框,你为什么要这么做? 该change的事件将在复选框反正被触发,你应该只关心一个。 但是,如果你必须从标签上的事件得到的复选框,然后你可以做手工。 如果事件目标的标签,那么你就知道该标签主题相关的输入。 这取决于你如何使用标签,您既可以选择input嵌套的内部元素label ,或者获得与在发现该ID的元素for的属性label

  3. 固定复选框的一种方式回报变化的 bug 前值是做this.blur()focus上的复选框的事件。

  4. 当你说“处理程序”,你的意思是onfocusin事件处理程序,或changeDelegator ? 这是正常的,看到一个focusin事件火重新激活选项卡时。 我不知道的知道为什么在事件被触发不止一次,所以我只是猜测:一个可能是有效输入接收的重点; 第二可能是该文件本身接收到焦点; 我不知道为什么第三个来电情况。 我不明白你说的“如果选中的状态实际改变,[...]如果我点击复选框直接只有一次”的意思。



Answer 2:

嗯,我有另一个打击它,我想出了一个相当不错的方法(在工作中它的伎俩-我试图复制我写的代码,但喝了几杯啤酒后,它可能包含了一些错误, 但精神保持不变

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!
});

我发现该于focusIn事件在某些情况下,广播的和复选框火两次。 使用保持着所有的复选框的选中实际状态的对象不是单个处理器更便宜,并允许元素的值更改后我只委派事件。

changeDelegator需要时功能只叫,但我这里张贴的匿名函数仍然被称为比我想它Waaaay更多,但这种方法仍然优于单独处理,服食。

我离开了选择,但我得到了他们的工作,太(类似于服用,我的代码盖具有2个对象的完整版本,而我做到了,所以在需要的时候,我可以标志一个id,火模糊事件,客户端重定向)。
在运行结束时,即使我已经学到了一些新花样,我从这个练习带走主要的是一个名为IE事情,可怕的,坚韧不拔的傀儡一个更加深刻的仇恨......但是,如果任何人可能曾经想委派在IE中更改事件,知道这是( 几乎 )可能



文章来源: JavaScript: How to simulate change event in internet explorer (delegation)