ОБНОВЛЕНИЕ: (резюме, скрипка и награда)
Этот вопрос не получил особого внимания, поэтому я собираюсь потратить на него репутацию. Я знаю, что склонен к излишней многословности как в ответах, так и в вопросах. Вот почему я пошел дальше и установил эту скрипку, которая, на мой взгляд, является достойным представлением кода, который я сейчас использую, чтобы приблизиться к всплывающему событию change
. Я пытаюсь решить несколько проблем:
- Событие
pseudo-change
не запускается для выбранного элемента, если только он не теряет фокус. В некоторых случаях клиент должен быть перенаправлен при выборе нового значения. Как мне этого добиться? - Обработчик вызывается как при нажатии меток, так и при нажатии самих флажков. Само по себе это то, что вы ожидаете, но из-за всплытия события (AFAIK) невозможно определить, какой элемент был нажат. Объект события IE не имеет свойства
realTarget
. - При изменении
checked
-состояния флажка в IE, щелкнув метку, все в порядке (хотя для этого требуются некоторые неприятные обходные пути), но при непосредственном щелчке флажка вызывается обработчик, но отмеченное состояние остается неизменным, пока я не нажму второй раз. Затем значение меняется, но обработчик не вызывается. - Когда я переключаюсь на другую вкладку и обратно, обработчик вызывается несколько раз. Трижды, если отмеченное состояние действительно изменилось, дважды, если я щелкнул чекбокс непосредственно только один раз.
Мы будем очень благодарны за любую информацию, которая может помочь мне решить одну или несколько из вышеперечисленных проблем. Пожалуйста, я не забыл добавить тег 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
для любого банкомата select, у которого есть фокус. Единственная проблема в том, что 99,9% пользователей нажимают на выбор, поэтому событие focusin
также запускает onclick.
Чтобы обойти это, я создал закрытие и передал ему текущий select-in-focus и его исходное значение в качестве аргументов. Но некоторые пользователи действительно используют свою клавиатуру, и эти пользователи часто переходят к следующему окну выбора, не меняя значения. Каждый раз привязывая новый прослушиватель 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;