.prop () против .attr () - PullRequest
       143

.prop () против .attr ()

2208 голосов
/ 03 мая 2011

Итак jQuery 1.6 имеет новую функцию prop().

$(selector).click(function(){
    //instead of:
    this.getAttribute('style');
    //do i use:
    $(this).prop('style');
    //or:
    $(this).attr('style');
})

или в этом случае они делают то же самое?

И если мне сделать придется переключиться на использование prop(), все старые вызовы attr() прервутся, если я переключусь на 1.6?

ОБНОВЛЕНИЕ

selector = '#id'

$(selector).click(function() {
    //instead of:
    var getAtt = this.getAttribute('style');
    //do i use:
    var thisProp = $(this).prop('style');
    //or:
    var thisAttr = $(this).attr('style');

    console.log(getAtt, thisProp, thisAttr);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
<div id='id' style="color: red;background: orange;">test</div>

(см. Также эту скрипту: http://jsfiddle.net/maniator/JpUF2/)

Консоль регистрирует getAttribute как строку, а attr какстрока, но prop как CSSStyleDeclaration, почему? И как это повлияет на мое кодирование в будущем?

Ответы [ 17 ]

1834 голосов
/ 04 мая 2011

Обновление 1 ноября 2012

Мой оригинальный ответ относится конкретно к jQuery 1.6. Мой совет остался прежним, но jQuery 1.6.1 немного изменил ситуацию: перед лицом предсказанной кучи неработающих веб-сайтов команда jQuery вернула attr() к чему-то близкому (но не совсем так) к своему старому поведению для логических атрибутов . Джон Ресиг также написал об этом в блоге . Я вижу трудности, с которыми они столкнулись, но все еще не согласен с его рекомендацией предпочесть attr().

Оригинальный ответ

Если вы когда-либо использовали jQuery, а не DOM напрямую, это может привести к путанице, хотя концептуально это определенно улучшение. Не очень хорошо для миллиардов сайтов, использующих jQuery, которые в результате этого изменения сломаются.

Подведу итоги по основным вопросам:

  • Вы обычно хотите prop(), а не attr().
  • В большинстве случаев prop() делает то, что делал attr(). Замена вызовов на attr() на prop() в вашем коде, как правило, будет работать.
  • Свойства, как правило, проще, чем атрибуты. Значением атрибута может быть только строка, тогда как свойство может быть любого типа. Например, свойство checked является логическим, свойство style является объектом с индивидуальными свойствами для каждого стиля, свойство size является числом.
  • Если существует свойство и атрибут с одинаковым именем, обычно при обновлении одного обновляется другое, но это не относится к определенным атрибутам входных данных, таким как value и checked: для этих атрибутов, свойство всегда представляет текущее состояние, в то время как атрибут (за исключением старых версий IE) соответствует значению по умолчанию / проверяемости ввода (отражено в свойстве defaultValue / defaultChecked).
  • Это изменение удаляет некоторые магические слои jQuery, застрявшие перед атрибутами и свойствами, что означает, что разработчикам jQuery придется немного узнать о различии между свойствами и атрибутами. Это хорошая вещь.

Если вы являетесь разработчиком jQuery и смущены всем этим бизнесом в отношении свойств и атрибутов, вам нужно сделать шаг назад и немного узнать об этом, поскольку jQuery больше не пытается так сильно оградить вас от этого материала. , Для авторитетного, но несколько сухого слова по теме, есть спецификации: DOM4 , HTML DOM , DOM Level 2 , DOM Level 3 . Документация Mozilla для DOM действительна для большинства современных браузеров и ее легче читать, чем спецификации, поэтому вы можете найти их DOM reference полезными. Есть раздел о свойствах элемента .

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

<input id="cb" type="checkbox" checked>
<input id="cb" type="checkbox" checked="checked">

Итак, как вы узнаете, установлен ли флажок в jQuery? Посмотрите на переполнение стека, и вы обычно найдете следующие предложения:

  • if ( $("#cb").attr("checked") === true ) {...}
  • if ( $("#cb").attr("checked") == "checked" ) {...}
  • if ( $("#cb").is(":checked") ) {...}

Это на самом деле самая простая вещь в мире, связанная с логическим свойством checked, которое существует и работает безупречно во всех основных скриптовых браузерах с 1995 года:

if (document.getElementById("cb").checked) {...}

Свойство также делает проверку или снятие флажка тривиальным:

document.getElementById("cb").checked = false

В jQuery 1.6 это однозначно становится

$("#cb").prop("checked", false)

Идея использования атрибута checked для сценариев флажка бесполезна и не нужна. Имущество - это то, что вам нужно.

  • Не очевидно, что для правильной установки или снятия флажка используется атрибут checked
  • Значение атрибута отражает состояние по умолчанию, а не текущее видимое состояние (за исключением некоторых более старых версий IE, что еще больше усложняет задачу).Атрибут ничего не говорит о том, установлен ли флажок на странице.См http://jsfiddle.net/VktA6/49/.
649 голосов
/ 04 мая 2011

Я думаю, Тим сказал это очень хорошо , но давайте сделаем шаг назад:

Элемент DOM - это объект, вещь в памяти. Как и большинство объектов в ООП, он имеет свойств . Он также отдельно имеет карту атрибутов, определенных для элемента (обычно исходящих из разметки, которую браузер считал для создания элемента). Некоторые из свойств элемента получают свои начальные значения из атрибутов с такими же или похожими именами (value получает свое начальное значение из атрибута "value"; href получает свое начальное значение из атрибута "href", но это не совсем то же значение; className из атрибута "class"). Другие свойства получают свои начальные значения другими способами: например, свойство parentNode получает свое значение в зависимости от того, что является его родительским элементом; элемент всегда имеет свойство style, независимо от того, имеет он атрибут style или нет.

Давайте рассмотрим этот якорь на странице http://example.com/testing.html:

<a href='foo.html' class='test one' name='fooAnchor' id='fooAnchor'>Hi</a>

Некоторое бесплатное искусство ASCII (и много чего не учитывается):

+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|             HTMLAnchorElement             |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| href:       "http://example.com/foo.html" |
| name:       "fooAnchor"                   |
| id:         "fooAnchor"                   |
| className:  "test one"                    |
| attributes:                               |
|    href:  "foo.html"                      |
|    name:  "fooAnchor"                     |
|    id:    "fooAnchor"                     |
|    class: "test one"                      |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

Обратите внимание, что свойства и атрибуты различны.

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

Когда я говорю о свойствах как о свойствах объекта, я не говорю абстрактно. Вот некоторый код не-JQuery:

var link = document.getElementById('fooAnchor');
alert(link.href);                 // alerts "http://example.com/foo.html"
alert(link.getAttribute("href")); // alerts "foo.html"

(Эти значения соответствуют большинству браузеров; есть некоторые различия.)

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

Как сказал Тим, в подавляющем большинстве времени мы хотим работать со свойствами. Частично это связано с тем, что их значения (даже их имена) имеют тенденцию быть более согласованными в разных браузерах. В основном мы хотим работать с атрибутами только в том случае, если с ним нет связанных свойств (пользовательских атрибутов) или когда мы знаем, что для этого конкретного атрибута атрибут и свойство не равны 1: 1 (как в случае href и «href»). "выше).

Стандартные свойства указаны в различных спецификациях DOM:

Эти спецификации имеют отличные индексы, и я рекомендую держать ссылки на них под рукой; Я использую их все время.

Настраиваемые атрибуты будут включать, например, любые атрибуты data-xyz, которые вы можете добавить к элементам для предоставления метаданных в свой код (теперь это действительно с HTML5, если вы придерживаетесь префикса data-) , (Последние версии jQuery предоставляют вам доступ к data-xyz элементам через функцию data, но эта функция , а не просто средство доступа к атрибутам data-xyz [она делает и больше, и меньше, чем это]; если вам не нужны его возможности, я бы использовал функцию attr для взаимодействия с атрибутом data-xyz.)

Функция attr использовала некоторую запутанную логику для получения того, что они думали, что вы хотели, вместо буквального получения атрибута. Это смешало понятия. Переход к prop и attr должен был их де-сплитовать. Вкратце, в v1.6.0 jQuery зашел слишком далеко в этом отношении, но функциональность была быстро добавлена ​​обратно к attr, чтобы справиться с общими ситуациями, когда люди используют attr, когда технически они должны использовать prop.

245 голосов
/ 04 мая 2011

Это изменение было долгое время для jQuery.В течение многих лет они довольствовались функцией с именем attr(), которая в основном извлекала свойства DOM, а не результат, который вы ожидаете от имени.Разделение attr() и prop() должно помочь устранить некоторую путаницу между атрибутами HTML и свойствами DOM.$.fn.prop() захватывает указанное свойство DOM, в то время как $.fn.attr() захватывает указанный атрибут HTML.

Чтобы полностью понять, как они работают, ниже приводится подробное объяснение различия между атрибутами HTML и свойствами DOM .:

Атрибуты HTML

Синтаксис:

<body onload="foo()">

Назначение: Позволяет разметке иметь связанные с ней данные для событий, рендеринга идругие цели.

Визуализация: HTML Attributes Атрибут класса показан здесь на теле.Он доступен через следующий код:

var attr;
attr = document.body.getAttribute("class");
//IE 8 Quirks and below
attr = document.body.getAttribute("className");

Атрибуты возвращаются в виде строки и могут быть несовместимы от браузера к браузеру.Тем не менее, они могут быть жизненно важны в некоторых ситуациях.Как показано выше, в IE 8 Quirks Mode (и ниже) ожидает имя свойства DOM в get / set / removeAttribute вместо имени атрибута.Это одна из многих причин, почему важно знать разницу.

Свойства DOM

Синтаксис:

document.body.onload = foo;

Цель: Предоставляет доступ к свойствам, которые принадлежат элементам узлов.Эти свойства похожи на атрибуты, но доступны только через JavaScript.Это важное различие, которое помогает прояснить роль свойств DOM. Обратите внимание, что атрибуты полностью отличаются от свойств , так как это назначение обработчика событий бесполезно и не получит событие (тело не имеет события onload, только атрибут onload).

Визуализация: DOM Properties

Здесь вы увидите список свойств на вкладке "DOM" в Firebug.Это свойства DOM.Вы сразу заметите довольно много из них, так как использовали их раньше, не зная об этом.Их значения - это то, что вы получите через JavaScript.

Документация

Пример

HTML: <textarea id="test" value="foo"></textarea>

JavaScript: alert($('#test').attr('value'));

В более ранних версиях jQuery это возвращает пустую строку.В 1.6 он возвращает правильное значение, foo.

Не взглянув на новый код для любой функции, я могу с уверенностью сказать, что путаница больше связана с различием между атрибутами HTML и DOMсвойства, чем с самим кодом.Надеюсь, это прояснило некоторые вещи для вас.

-Matt

239 голосов
/ 27 сентября 2011

Свойство находится в DOM; атрибут в HTML, который анализируется в DOM.

Подробнее

Если вы измените атрибут, это изменение будет отражено в DOM (иногда с другим именем).

Пример: изменение атрибута class тега изменит свойство className этого тега в DOM. Если у вас нет атрибута в теге, у вас все еще есть соответствующее свойство DOM со значением по умолчанию или пустым.

Пример. Хотя у вашего тега нет атрибута class, свойство DOM className существует с пустым строковым значением.

редактировать

Если вы измените одно, другое будет изменено контроллером, и наоборот. Этот контроллер не в jQuery, а в собственном коде браузера.

137 голосов
/ 19 мая 2011

Это только различие между атрибутами HTML и объектами DOM, которое вызывает путаницу.Для тех, кому удобно работать с собственными свойствами элементов DOM, таких как this.src this.value this.checked и т. Д., .prop - очень теплый прием в семье.Для других это просто дополнительный слой путаницы.Давайте разберемся с этим.

Самый простой способ увидеть разницу между .attr и .prop - это следующий пример:

<input blah="hello">
  1. $('input').attr('blah'): возвращает 'hello' как ожидалось.Здесь нет сюрпризов.
  2. $('input').prop('blah'): возвращает undefined - потому что он пытается выполнить [HTMLInputElement].blah - и такого свойства для этого объекта DOM не существует.Он существует только в области видимости как атрибут этого элемента, т.е. [HTMLInputElement].getAttribute('blah')

Теперь мы изменим несколько вещей, например:

$('input').attr('blah', 'apple');
$('input').prop('blah', 'pear');
  1. $('input').attr('blah'): возвращает 'apple' а?Почему бы не "груша", как это было установлено последним на этом элементе.Поскольку свойство было изменено для входного атрибута, а не для самого входного элемента DOM - они в основном почти работают независимо друг от друга.
  2. $('input').prop('blah'): возвращает 'pear'

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

См. Скрипку, демонстрирующую разницу: http://jsfiddle.net/garreh/uLQXc/


.attr против .prop:

Раунд 1: стиль

<input style="font:arial;"/>
  • .attr('style') - возвращает встроенные стили для сопоставленного элемента, т.е. "font:arial;"
  • .prop('style') - возвращает объект объявления стиля, т.е. CSSStyleDeclaration

Round 2: значение

<input value="hello" type="text"/>   

$('input').prop('value', 'i changed the value');
  • .attr('value') - возврат 'hello' *
  • .prop('value') - возврат 'i changed the value'

* Примечание: jQuery по этой причине имеет метод .val(), который внутренне эквивалентен .prop('value')

51 голосов
/ 16 июля 2014

TL; DR

В большинстве случаев используйте prop() over attr().

Свойство * - текущее состояниеэлемента ввода.Атрибут является значением по умолчанию.

Свойство может содержать объекты разных типов.Атрибут может содержать только строки

35 голосов

Грязная проверка

Эта концепция дает пример, в котором разница заметна: http://www.w3.org/TR/html5/forms.html#concept-input-checked-dirty

Попробуйте:

  • нажмите кнопку. Оба флажка были проверены.
  • снимите оба флажка.
  • нажмите кнопку еще раз. Только флажок prop был отмечен. BANG!

$('button').on('click', function() {
  $('#attr').attr('checked', 'checked')
  $('#prop').prop('checked', true)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>attr <input id="attr" type="checkbox"></label>
<label>prop <input id="prop" type="checkbox"></label>
<button type="button">Set checked attr and prop.</button>

Для некоторых атрибутов, таких как disabled на button, добавление или удаление атрибута содержимого disabled="disabled" всегда переключает свойство (называемое атрибутом IDL в HTML5), поскольку http://www.w3.org/TR/html5/forms.html#attr-fe-disabled говорит:

Отключенный атрибут IDL должен отражать отключенный атрибут содержимого.

так что вам может это сойти с рук, хотя это уродливо, поскольку без необходимости модифицирует HTML.

Для других атрибутов, таких как checked="checked" на input type="checkbox", все нарушается, потому что если вы нажмете на него, он станет грязным, а затем добавление или удаление атрибута checked="checked" content больше не переключает checkness .

Вот почему вы должны использовать в основном .prop, так как он напрямую влияет на эффективное свойство, а не полагаться на сложные побочные эффекты изменения HTML.

32 голосов
/ 03 мая 2011

Все в документ :

Разница между атрибутами и свойствами может быть важна в определенных ситуациях.До версии jQuery 1.6 метод .attr () иногда учитывал значения свойств при извлечении некоторых атрибутов, что могло вызвать противоречивое поведение.Начиная с jQuery 1.6, метод .prop () предоставляет способ явного получения значений свойств, в то время как .attr () возвращает атрибуты.

Так что используйте prop!

27 голосов
/ 12 июня 2015

атрибуты находятся в вашем HTML текстовом документе / файле (== представьте, что это результат анализа вашей HTML-разметки), тогда как
свойства находятся в HTML DOM-дереве (== в основном фактическое свойство некоторого объекта в смысле JS).

Важно, что многие из них синхронизируются (если вы обновите свойство class, атрибут class в html также будет обновлен; и в противном случае). Но некоторые атрибуты могут быть синхронизированы с неожиданными свойствами - например, атрибут checked соответствует свойству defaultChecked, так что

  • Установка флажка вручную изменит значение .prop('checked'), но не изменит значения .attr('checked') и .prop('defaultChecked')
  • настройка $('#input').prop('defaultChecked', true) также изменит .attr('checked'), но это не будет видно на элементе.

Правило большого пальца: : метод .prop() следует использовать для логических атрибутов / свойств и для свойств, которых нет в html. (например, window.location). Все остальные атрибуты (те, которые вы можете увидеть в html) можно и нужно продолжать манипулировать с помощью .attr() метод. (http://blog.jquery.com/2011/05/10/jquery-1-6-1-rc-1-released/)

А вот таблица, которая показывает, где .prop() предпочтительнее (хотя .attr() все еще можно использовать).

table with preferred usage


Почему вы иногда хотите использовать .prop () вместо .attr (), где это официально рекомендовано?

  1. .prop() может вернуть любой тип - строка, целое число, логическое значение; в то время как .attr() всегда возвращает строку.
  2. .prop() примерно в 2,5 раза быстрее, чем .attr().
18 голосов
/ 08 декабря 2015

.attr():

  • Получить значение атрибута для первого элемента в наборе совпадающих элементов.
  • Дает значениеэлемент, как это было определено в html при загрузке страницы

.prop():

  • Получить значение свойства для первого элемента внабор соответствующих элементов.
  • Предоставляет обновленные значения элементов, которые изменяются с помощью javascript / jquery
...