关于 javascript:jQuery .prop() 返回未定义,而 .attr() 对数据按预期工作-*

jQuery .prop() returns undefined, while .attr() works as expected for data-*

我只是想从两个元素中获取几个属性。从 input 元素获取属性 value 可以按预期工作。问题在于从 button 元素获取属性 data-detail 属性。使用 .prop() 时返回 undefined,但使用 .attr().

时按预期工作

谁能解释我目睹的这种奇怪行为?

HTML

1
2
3
4
5
6
7
    <label for="firstName">First name</label>
   
        <button id="editFirstName" class="btn ctaBtn greenBtn editBtn">Edit</button>
        <button class="btn ctaBtn greenBtn saveBtn" data-detail="firstName">Save</button>
        <button id="closeFirstName" class="btn ctaBtn greyBtn closeBtn">Close</button>
   
    <input type="text" id="firstName" name="firstName" value="[+firstName+]" readonly>

JS

1
2
3
4
5
6
7
8
9
$(".saveBtn").on("click", function() {
    var saveBtn = $(this);
    // The following statement yields undefined. When using .attr() it works as expected.
    var detail = saveBtn.prop("data-detail");
    var relevantInput = saveBtn.parent().next();
    // The following statement works as expected.
    var value = relevantInput.prop("value");
    // ...
});


那是因为 HTML 元素上没有 data-detail 属性。

以下是 .data()、.prop() 和 .attr() 的简要说明:
DOM 元素是一个具有 methodsproperties(来自 DOM)和 attributes(来自渲染的 HTML)的对象。其中一些 properties 通过 attributes id->id, class->className, title->title, style->style etc. 获得他们的 initial value
考虑这个元素:<input type="checkbox" checked data-detail="somedata" >
以下结果将是:

1
2
$('input').prop('id'); // =>""-empty string, property id exist on the element (defined by DOM) , but is not set.
$('input').attr('id');// => undefined - doesn't exist.

如果您执行以下操作:

1
2
3
$('input').attr('id',"someID");
$('input').prop('id'); // => "someID"
$('input').attr('id'); // => "someID"

还有:

1
2
3
$('input').prop('id',"someOtherID");
$('input').prop('id');// => "someOtherID"
$('input').attr('id');// => "someOtherID"

So, some attributes and properties have 1:1 mapping. (change of
the attr result change of the prop and vice versa).

考虑以下内容:<input type="text" data-detail="somedata" value="someValue">

1
2
3
$('input').prop('value'); // => "someValue"
$('input').val();         // => "someValue"
$('input').attr('value'); // => "someValue"

如果你这样做:

1
2
3
4
5
6
7
8
9
$('input').prop('value','newVal');

// or

$('input').val('newVal');

$('input').prop('value'); // =>"newVal"    -value of the property
$('input').val();         // =>"newVal"    -value of the property
$('input').attr('value'); // =>"someValue" -value of the attr didn't change, since in this case it is not 1:1 mapping (change of the prop value doesn't reflect to the attribute value).

.data() 的情况

1) 获取方式:

- 请记住 attribute namedata-*property namedataset,所以:

1
<input type="checkbox" data-detail="somedata">
1
2
3
4
5
6
 $('input')[0].dataset; //=> [object DOMStringMap] { detail:"somedata"}
 $('input')[0].dataset.detail; // =>"somedata"
 $('input').prop('dataset'); //=>[object DOMStringMap] { detail:"somedata"}
 $('input').prop('dataset').detail; // =>"somedata"
 $('input').data('detail'); // =>"somedata"
 $('input').attr('data-detail');  //  =>"somedata"

2) 设置方法:

I) $('input').prop('dataset').detail='newData';

1
2
3
4
 $('input').prop('dataset');  //=> [object DOMStringMap] { detail:"newData"}
 $('input').prop('dataset').detail; // =>"newData"
 $('input').attr('data-detail'); // =>"newData"
 $('input').data('detail'); // =>"newData"

II) $('input').attr('data-detail','newData');

1
2
3
4
 $('input').prop('dataset');  //=> [object DOMStringMap] { detail:"newData"}
 $('input').prop('dataset').detail; // =>"newData"
 $('input').attr('data-detail'); // =>"newData"
 $('input').data('detail'); // =>"newData"

So you can see that here is 1:1 mapping, attr change reflects prop and
vice versa.

但是检查第三种方式:

III) $('input').data('detail','newData');

1
2
3
4
 $('input').prop('dataset'); // =>  [object DOMStringMap] { detail:"somedata"}
 $('input').prop('dataset').detail; // =>"somedata"
 $('input').attr('data-detail'); // =>"somedata"
 $('input').data('detail');  // =>"newData"    <-----******

那么,这里发生了什么?

$(elem).data(key, value) does not change the HTML5 data-* attributes
of the element. It stores its values in $.cache internally.

所以为了获得 data-* 你永远不会出错 .data() :

1
2
3
4
5
6
7
$(".saveBtn").on("click", function() {
    var saveBtn = $(this);
    var detail = saveBtn.data("detail");
    var relevantInput = saveBtn.parent().next();
    var value = relevantInput.prop("value");

});