Почему свойство onclick, установленное с помощью setAttribute, не работает в IE?

Загляните в эту проблему сегодня, разместив сообщение на случай, если у кого-то есть такая же проблема.

var execBtn = document.createElement('input');
execBtn.setAttribute("type", "button");
execBtn.setAttribute("id", "execBtn");
execBtn.setAttribute("value", "Execute");
execBtn.setAttribute("onclick", "runCommand();");

Оказывается, IE запускает onclick на динамически сгенерированном элементе, мы не можем использовать setAttribute. Вместо этого нам нужно установить свойство onclick для объекта с анонимной функцией, заключающей в себе код, который мы хотим запустить.

execBtn.onclick = function() { runCommand() };

ПЛОХИЕ ИДЕИ:

Ты можешь сделать

execBtn.setAttribute("onclick", function() { runCommand() });

но он сломается в IE в нестандартном режиме, согласно @scunliffe.

Вы вообще не можете этого сделать

execBtn.setAttribute("onclick", runCommand() ); 

потому что он выполняется немедленно и устанавливает результат runCommand () как значение атрибута onClick, и вы не можете этого сделать

execBtn.setAttribute("onclick", runCommand);

Использование атрибутов HTML в качестве обработчиков событий запрещено. Сделайте это так: execBtn.onclick = runCommand;

Josh Stodola 01.07.2009 21:30
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
49
1
161 480
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Ты пробовал:

    execBtn.setAttribute("onclick", function() { runCommand() });

это «не должно» работать в IE6 / IE7 или IE8 в нестандартном режиме. Для IE вам необходимо использовать: execBtn.onclick = function () {...}

scunliffe 19.09.2008 06:26

Напишите функцию в строке, и интерпретатор будет достаточно умен, чтобы знать, что вы пишете функцию. Сделайте это так, и предполагается, что это просто строка (что технически и есть).

Можете ли вы добавить пример кода того, что вы имеете в виду? Разве это не одна из «плохих идей» выше?

Peter Hilton 29.09.2008 20:52

Не имеет отношения к проблеме onclick, но также имеет отношение:

Для атрибутов html, имя которых противоречит зарезервированным словам javascript, выбирается альтернативное имя, например. <div class=''>, но div.className, или <label for='...'>, но label.htmlFor.

В разумных браузерах это не влияет на setAttribute. Итак, в gecko и webkit вы бы назвали div.setAttribute('class', 'foo'), но в IE вместо этого вы должны использовать имя свойства javascript, поэтому div.setAttribute('className', 'foo').

Существует набор атрибутов БОЛЬШОЙ, который вы не могу установить в IE используете, используя .setAttribute (), который включает каждый встроенный обработчик событий.

Подробнее см. Здесь:

http://webbugtrack.blogspot.com/2007/08/bug-242-setattribute-doesnt-always-work.html

Ответ принят как подходящий

чтобы это работало как в FF, так и в IE, вы должны написать оба пути:


    button_element.setAttribute('onclick','doSomething();'); // for FF
    button_element.onclick = function() {doSomething();}; // for IE

спасибо эта почта.

ОБНОВИТЬ: Это демонстрирует, что иногда является необходимо использовать setAttribute! Этот метод работает, если вам нужно взять исходный атрибут onclick из HTML и добавить его в событие onclick, чтобы его не переопределить:

// get old onclick attribute
var onclick = button_element.getAttribute("onclick");  

// if onclick is not a function, it's not IE7, so use setAttribute
if (typeof(onclick) != "function") { 
    button_element.setAttribute('onclick','doSomething();' + onclick); // for FF,IE8,Chrome

// if onclick is a function, use the IE7 method and call onclick() in the anonymous function
} else {
    button_element.onclick = function() { 
        doSomething();
        onclick();
    }; // for IE7
}

button_element.onclick = function () .. работает как в IE, так и в Firefox. В этом отношении он также работает в Opera, Safari и Chrome. Любая причина, по которой необходим setAttribute (для Firefox)?

slebetman 10.06.2010 10:38

Способ onclick отлично работает как в FF, так и в IE. Нет причин использовать версию setAttribute.

bobince 11.07.2010 05:04

@bobince - я обновил этот ответ, чтобы продемонстрировать, что существуют случаи находятся, в которых вам нужно использовать setAttribute. В IE8 +, FF, Chrome getAttribute ("onclick") возвращает строку, тогда как в IE7 эта строка заключена в функцию и должна вызываться с помощью onclick ();

jmort253 08.04.2011 04:39

Но в чем вообще преимущество getAttribute / setAttribute? Использование свойства .onclick вместо получения и установки работает во всех браузерах и не вызывает проблемных различий в области видимости.

bobince 09.04.2011 12:24

Это все еще актуально?

redfelix 24.03.2018 04:04

Рассматривали ли вы прослушиватель событий, а не устанавливали атрибут? Среди прочего, он позволяет передавать параметры, с чем я столкнулся при попытке сделать это. Вам все равно придется сделать это дважды для IE и Mozilla:

function makeEvent(element, callback, param, event) {
    function local() {
        return callback(param);
    }

    if (element.addEventListener) {
        //Mozilla
        element.addEventListener(event,local,false);
    } else if (element.attachEvent) {
        //IE
        element.attachEvent("on"+event,local);
    }
}

makeEvent(execBtn, alert, "hey buddy, what's up?", "click");

Просто позвольте событию иметь имя вроде «щелчок» или «наведение курсора».

Я сделал это, чтобы обойти это и двигаться дальше, в моем случае я не использую элемент input, вместо этого я использую изображение, когда я пытался установить атрибут «onclick» для этого изображения, я столкнулся с той же проблемой, поэтому Я попытался обернуть изображение элементом «а» и сделать ссылку на функцию вот так.

var rowIndex = 1;
var linkDeleter = document.createElement('a');
linkDeleter.setAttribute('href', "javascript:function(" + rowIndex + ");");

var imgDeleter = document.createElement('img');
imgDeleter.setAttribute('alt', "Delete");
imgDeleter.setAttribute('src', "Imagenes/DeleteHS.png");
imgDeleter.setAttribute('border', "0");

linkDeleter.appendChild(imgDeleter);

Или вы можете использовать jQuery и избежать всех этих проблем:

var execBtn = $("<input>", {
       type: "button",
       id: "execBtn",
       value: "Execute"
    })
    .click(runCommand);        

jQuery также позаботится обо всех кроссбраузерных проблемах.

В некоторых случаях перечисленные здесь примеры не работали для меня в Internet Explorer.

Поскольку вы должны установить свойство с помощью такого метода (без скобок)

HtmlElement.onclick = myMethod;

это не сработает, если вам нужно передать имя объекта или даже параметры. Для Internet Explorer вы должны создать новый объект во время выполнения:

HtmlElement.onclick = new Function('myMethod(' + someParameter + ')');

Работает также в других браузерах.

Это ужасный способ передачи параметров. Он не будет работать ни с чем, кроме основных типов данных, и даже тогда вам понадобится экранирование в стиле JSON, чтобы превратить их в литералы. Всегда используйте выражение встроенной функции (onclick= function() { myMethod(someParameter); }) вместо new Function().

bobince 11.07.2010 05:06

Это потрясающая функция для кроссбраузерной привязки событий.

Получил от http://js.isite.net.au/snippets/addevent

С его помощью вы можете просто сделать Events.addEvent(element, event, function); и не беспокоиться!

Например: (http://jsfiddle.net/Zxeka/)

function hello() {
    alert('Hello');
}

var button = document.createElement('input');
button.value = "Hello";
button.type = "button";

Events.addEvent(input_0, "click", hello);

document.body.appendChild(button);

Вот функция:

// We create a function which is called immediately,
// returning the actual function object.  This allows us to
// work in a separate scope and only return the functions
// we require.
var Events = (function() {

  // For DOM2-compliant browsers.
  function addEventW3C(el, ev, f) {
    // Since IE only supports bubbling, for
    // compatibility we can't use capturing here.
    return el.addEventListener(ev, f, false);
  }

  function removeEventW3C(el, ev, f) {
    el.removeEventListener(ev, f, false);
  }

  // The function as required by IE.
  function addEventIE(el, ev, f) {
    // This is to work around a bug in IE whereby the
    // current element doesn't get passed as context.
    // We pass it via closure instead and set it as the
    // context using call().
    // This needs to be stored for removeEvent().
    // We also store the original wrapped function as a
    // property, _w.
    ((el._evts = el._evts || [])[el._evts.length]
        = function(e) { return f.call(el, e); })._w = f;

    // We prepend "on" to the event name.
    return el.attachEvent("on" + ev,
        el._evts[el._evts.length - 1]);
  }

  function removeEventIE(el, ev, f) {
    for (var evts = el._evts || [], i = evts.length; i--; )
      if (evts[i]._w === f)
        el.detachEvent("on" + ev, evts.splice(i, 1)[0]);
  }

  // A handler to call all events we've registered
  // on an element for legacy browsers.
  function addEventLegacyHandler(e) {
    var evts = this._evts[e.type];
    for (var i = 0; i < evts.length; ++i)
      if (!evts[i].call(this, e || event))
        return false;
  }

  // For older browsers.  We basically reimplement
  // attachEvent().
  function addEventLegacy(el, ev, f) {
    if (!el._evts)
      el._evts = {};

    if (!el._evts[ev])
      el._evts[ev] = [];

    el._evts[ev].push(f);

    return true;
  }

  function removeEventLegacy(el, ev, f) {
    // Loop through the handlers for this event type
    // and remove them if they match f.
    for (var evts = el._evts[ev] || [], i = evts.length; i--; )
      if (evts[i] === f)
        evts.splice(i, 1);
  }

  // Select the appropriate functions based on what's
  // available on the window object and return them.
  return window.addEventListener
      ? {addEvent: addEventW3C, removeEvent: removeEventW3C}
      : window.attachEvent
          ? {addEvent: addEventIE, removeEvent: removeEventIE}
          : {addEvent: addEventLegacy, removeEvent: removeEventLegacy};
})();

Если вы не хотите использовать такую ​​большую функцию, это должно работать почти для всех браузеров, включая IE:

if (el.addEventListener) { 
    el.addEventListener('click', function, false); 
} else if (el.attachEvent) { 
    el.attachEvent('onclick', function); 
} 

В ответ на вопрос Крейга. Вам нужно будет создать новый элемент и скопировать атрибуты старого элемента. Эта функция должна выполнять свою работу: (источник)

function changeInputType(oldObject, oType) {
  var newObject = document.createElement('input');
  newObject.type = oType;
  if (oldObject.size) newObject.size = oldObject.size;
  if (oldObject.value) newObject.value = oldObject.value;
  if (oldObject.name) newObject.name = oldObject.name;
  if (oldObject.id) newObject.id = oldObject.id;
  if (oldObject.className) newObject.className = oldObject.className;
  oldObject.parentNode.replaceChild(newObject,oldObject);
  return newObject;
}

прекрасно работает!

использование обоих способов теперь кажется ненужным:

execBtn.onclick = function() { runCommand() };

очевидно, работает во всех текущих браузерах.

протестировано в текущих версиях Firefox, IE, Safari, Opera, Chrome в Windows; Fire Fox и Epiphany в Ubuntu; не тестировался на Mac или мобильных системах.

  • Крейг: Я бы попробовал «document.getElementById (ID) .type = 'password';
  • Кто-нибудь проверял подход "AddEventListener" на разных движках?

function CheckBrowser(){
    if (navigator.userAgent.match(/Android/i)!=null||
        navigator.userAgent.match(/BlackBerry/i)!=null||
        navigator.userAgent.match(/iPhone|iPad|iPod/i)!=null||
        navigator.userAgent.match(/Nokia/i)!=null||
        navigator.userAgent.match(/Opera M/i)!=null||
        navigator.userAgent.match(/Chrome/i)!=null)
        {
            return 'OTHER';
    }else{
            return 'IE';
    }
}


function AddButt(i){
    var new_butt = document.createElement('input');
    new_butt.setAttribute('type','button');
    new_butt.setAttribute('value','Delete Item');
    new_butt.setAttribute('id', 'answer_del_'+i);
    if (CheckBrowser()=='IE'){
        new_butt.setAttribute("onclick", function() { DelElemAnswer(i) });
    }else{
        new_butt.setAttribute('onclick','javascript:DelElemAnswer('+i+');');
    }
}

На самом деле, насколько мне известно, динамически создаваемые встроенные обработчики событий ДЕЙСТВИТЕЛЬНО работают в Internet Explorer 8 при создании с помощью команды x.setAttribute(); вам просто нужно правильно разместить их в коде JavaScript. Наткнулся на решение вашей (и моей) проблемы здесь.

Когда я переместил все свои операторы, содержащие x.appendChild(), в их правильные позиции (то есть сразу после последней команды setAttribute в их группах), я обнаружил, что КАЖДЫЙ отдельный атрибут setAttribute работал в IE8, как и предполагалось, включая все входные атрибуты формы (включая " name "и" type ", а также мои обработчики событий" onclick ").

Я нашел это весьма примечательным, поскольку все, что у меня было в IE до того, как я это сделал, - это мусор, отображаемый на экране, и одна ошибка за другой. Кроме того, я обнаружил, что каждый setAttribute по-прежнему работает и в других браузерах, поэтому, если вы просто запомните эту простую практику кодирования, в большинстве случаев вам будет хорошо.

Однако это решение не сработает, если вам нужно изменить какие-либо атрибуты на лету, поскольку они не могут быть изменены в IE после того, как их HTML-элемент был добавлен в DOM; в этом случае я мог бы предположить, что нужно было бы удалить элемент из DOM, а затем воссоздать его и его атрибуты (в правильном порядке, конечно!), чтобы они работали правильно и не выдавали никаких ошибок.

Другие вопросы по теме