setAttribute, onClick и кроссбраузерная совместимость

Я прочитал несколько сообщений об этом, но ни один из них не дал твердого ответа. Вот мой код:

// button creation
onew = document.createElement('input');
onew.setAttribute("type", "button");
onew.setAttribute("value", "hosts");
onew.onclick = function(){fnDisplay_Computers("'" + alines[i] + "'"); }; // ie
onew.setAttribute("onclick", "fnDisplay_Computers('" + alines[i] + "')"); // mozilla
odiv.appendChild(onew);

Теперь метод setAttribute () (с комментарием mozilla) отлично работает в mozilla, но только если он появляется ПОСЛЕ строчки над ним. Другими словами, кажется, что по умолчанию используется то, что было установлено последним. Метод .onclick (с комментарием ie) не работает в любом случае, я использую его неправильно?

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

Короче говоря, я не могу заставить параметр onclick работать согласованно между IE / Mozilla.

- Николай


person Nicholas Kreidberg    schedule 14.04.2009    source источник


Ответы (4)


Обычно я использую что-то вроде:

onew.onclick = new Function("fnDisplay_Computers('" + alines[i] + "')");

это должно работать как в IE, так и в Firefox.

person Enrico Murru    schedule 14.04.2009
comment
Это работает отлично, можете ли вы объяснить, почему его установка как новая функция (даже если функция fnDisplay_Computers () уже определена, решает проблему? - person Nicholas Kreidberg; 14.04.2009
comment
Я думаю, что это проблема используемого типа данных и ссылки на новую функцию, связанную с новым методом onclick ... но я действительно не знаю точного ответа, извините! - person Enrico Murru; 14.04.2009
comment
Красивый! Спасибо! Были проблемы с IE7, это решило это отлично. - person Yuriy Galanter; 15.08.2012

onew.setAttribute («тип», «кнопка»);

Никогда не используйте setAttribute в HTML-документах. IE во многих случаях сильно ошибается, а свойства DOM-HTML короче, быстрее и легче читаются:

onew.type= 'button';

onew.onclick = function () {fnDisplay_Computers ("'" + alines [i] + "'"); }; // т.е.

Что такое alines? Почему вы конвертируете его в строку и заключаете в одинарные кавычки? Похоже, вы пытаетесь сделать что-то отвратительное, связанное с оценкой кода в строке (это то, что вы делаете ниже в версии «onew.setAttribute»). Анализировать код JavaScript в строках почти всегда неправильно; Избегайте этого, как чумы. В приведенном выше случае IE должен делать то же самое, что и Firefox: он не должен работать.

Если ‘alines [i]’ является строкой, я предполагаю, что вы пытаетесь сделать так, чтобы он запомнил эту строку, создав строку кода, которая будет оценивать в JavaScript исходную строку. Но:

"'" + alines[i] + "'"

недостаточно. Что произойдет, если в строке «alines [i]» стоит апостроф или обратная косая черта?

'O'Reilly'

у вас есть синтаксическая ошибка и возможная дыра в безопасности. Теперь вы можете сделать что-нибудь утомительное и утомительное, например:

"'" + alines[i].split('\\').join('\\\\').split("'").join("\\'") + "'"

чтобы попытаться избежать строки, но это некрасиво и не будет работать для других типов данных. Вы даже можете попросить JavaScript сделать это за вас:

uneval(alines[i])

Но не все объекты можно даже преобразовать в оцениваемые исходные строки JavaScript; в основном весь подход обречен на провал.

Если вы просто хотите, чтобы обратный вызов onclick вызывал функцию с параметром, обычно нужно написать код простым способом:

onew.onclick= function() {
    fnDisplay_Computers(alines[i]);
};

Обычно это сработает, и вы этого хотите. Однако здесь есть небольшая складка, которая может сбить вас с толку, заставив задуматься о дурацком подходе со струнами.

А именно, если «i» в данном случае является переменной включающего цикла «for», ссылка на «alines [i]» не будет делать то, что вы думаете. Функция обратного вызова получит доступ к «i», когда произойдет щелчок - то есть после завершения цикла. На этом этапе для переменной «i» останется то значение, которое она имела в конце цикла, поэтому «alines [i]» всегда будет последним элементом «alines», независимо от того, какой элемент «onew» был нажат.

(См., Например, Как исправить проблему закрытия в ActionScript 3 (AS3) для обсуждения этого вопроса. Это одна из основных причин путаница с закрытием как в JavaScript, так и в Python, и когда-нибудь ее действительно следует исправить на уровне языка.)

Вы можете обойти проблему цикла, инкапсулируя замыкание в его собственную функцию, например:

function callbackWithArgs(f, args) {
    return function() { f.apply(window, args); }
}

// ...

onew.onclick= callbackWithArgs(fnDisplay_Computers, [alines[i]]);

А в более поздней версии JavaScript вы сможете просто сказать:

onew.onclick= fnDisplay_Computers.bind(window, alines[i]);

Если вы хотите иметь возможность использовать Function.bind () в браузерах сегодня, вы можете получить реализацию из Прототип фреймворка или просто используйте:

if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        var args= Array.prototype.slice.call(arguments, 1);
        return function() {
            return that.apply(owner,
                args.length===0? arguments : arguments.length===0? args :
                args.concat(Array.prototype.slice.call(arguments, 0))
            );
        };
    };
}
person bobince    schedule 14.04.2009
comment
ОТЛИЧНО ответ, вау, вы охватили все базы. К счастью, все строки дезинфицируются еще до того, как на alines [x] когда-либо будут ссылаться, а входящие значения в любом случае являются частью определенного массива, так что об этом не нужно беспокоиться. - person Nicholas Kreidberg; 15.04.2009
comment
Можно ли с уверенностью сказать следующее: onclick - это обработчик событий, а НЕ атрибут, поэтому установка его в качестве атрибута не приведет к созданию необходимого обработчика событий, чтобы он работал, по крайней мере, в IE? - person Nicholas Kreidberg; 15.04.2009
comment
да. На самом деле это свойство обработчика событий встроенного скрипта (типа Function) и атрибут уровня документа (типа String), но поскольку IE ‹8 не понимает, как работают атрибуты, он пытается установить обработчик событий в String вместо скомпилированной из него функции, что не работает. - person bobince; 15.04.2009
comment
Отлично, я понял. Большое спасибо за ваш вклад, bobince. - person Nicholas Kreidberg; 15.04.2009

Используйте функцию addEventListener() с «click» в качестве аргумента type для Mozilla. браузеры и attachEvent() с "onclick" как sEvent аргумент для IE; Я считаю, что лучше использовать инструкцию try / catch, например:

try {
  onew.attachEvent("onclick", //For IE
                   function(){fnDisplay_Computers("'" + alines[i] + "'"); });
}
catch(e) {
  onew.addEventListener("click", //For Mozilla-based browsers
                   function(){fnDisplay_Computers("'" + alines[i] + "'"); },
                   false);
}
person Alex Rozanski    schedule 14.04.2009

Я думаю, что №3 слишком сильно протестует. Во многих ситуациях я создаю таблицу динамически, и мне нужно передать параметры функции обратного вызова. Это не типичная проблема, поскольку моя переменная parm является целочисленным индексом для рассматриваемой строки таблицы. Вот код с переменным и фиксированным параметром, который кажется кроссбраузерным:

for (i = 0; i < arrTableData.length; i++) {
    eleTR = objTable.insertRow(i + 1);
    cell = eleTR.insertCell(0);
    cell.width = "21";
    var myElement = document.createElement('img');
    myElement.setAttribute('src', 'images/button_down.gif');
    myElement.setAttribute('alt', 'Move item down');
    myElement.onclick = new Function('moveItem(' + i + ',0)');
    cell.appendChild(myElement);
}
person marty nickel    schedule 24.04.2010