jQuery .data () không hoạt động, nhưng .attr () thì có


107

Thứ lỗi cho tôi vì đã không nói rõ hơn về điều này. Tôi có một lỗi kỳ lạ như vậy. Sau khi tải tài liệu, tôi lặp lại một số phần tử mà ban đầu có data-itemname=""và tôi đặt các giá trị đó bằng cách sử dụng .attr("data-itemname", "someValue").

Vấn đề: Sau này khi tôi lặp qua các phần tử đó, nếu tôi làm elem.data().itemname, tôi nhận được "", nhưng nếu tôi làm elem.attr("data-itemname"), tôi nhận được "someValue". Nó giống như .data()getter của jQuery chỉ nhận các phần tử được đặt ban đầu để chứa một số giá trị, nhưng nếu ban đầu chúng trống và sau đó được đặt, thì sau .data()này sẽ không nhận được giá trị.

Tôi đã cố gắng tạo lại lỗi này nhưng không thể.

Biên tập

Tôi đã tạo lại lỗi! http://jsbin.com/ihuhep/edit#javascript,html,live

Ngoài ra, các đoạn trích từ liên kết trên ...

JS:

var theaters = [
    { name: "theater A", theaterId: 5 },
    { name: "theater B", theaterId: 17 }
];

$("#theaters").html(
    $("#theaterTmpl").render(theaters)
);

// DOES NOT WORK - .data("name", "val") does NOT set the val
var theaterA = $("[data-theaterid='5']");
theaterA.find(".someLink").data("tofilllater", "theater5link"); // this does NOT set data-tofilllater
$(".someLink[data-tofilllater='theater5link']").html("changed link text"); // never gets changed

// WORKS - .attr("data-name", "val") DOES set val
var theaterB = $("[data-theaterid='17']");
theaterB.find(".someLink").attr("data-tofilllater", "theater17link"); // this does set data-tofilllater
$(".someLink[data-tofilllater='theater17link']").html("changed link text");

HTML:

<body>
    <div id="theaters"></div>
</body>

<script id="theaterTmpl" type="text/x-jquery-tmpl">
    <div class="theater" data-theaterid="{{=theaterId}}">
        <h2>{{=name}}</h2>
        <a href="#" class="someLink" data-tofilllater="">need to change this text</a>
    </div>
</script>

4
Cố gắng hơn nữa để tái tạo lỗi :-)
dkamins

1
Phải elem.data("itemname")không elem.data().itemname?
Hogan

trong khi elem.data (). itemname sẽ cho phép bạn đọc giá trị mà nó KHÔNG cho phép bạn đặt giá trị. (Do elem.data().itemname = somevalue;đó không thay đổi dữ liệu cơ bản.)
Hogan

@dkamins - Tôi đã tạo lại lỗi, vui lòng xem phiên bản đã chỉnh sửa.
Ian Davis

Câu trả lời:


210

Tôi đã gặp phải một "lỗi" tương tự cách đây vài ngày khi làm việc với .data().attr('data-name')đối với các thuộc tính dữ liệu HTML5.

Hành vi bạn đang mô tả không phải là một lỗi, mà là do thiết kế.

Lời .data()gọi này rất đặc biệt - nó không chỉ truy xuất các thuộc tính dữ liệu HTML5 mà còn cố gắng đánh giá / phân tích cú pháp các thuộc tính. Vì vậy, với một thuộc tính như data-myjson='{"hello":"world"}'khi truy xuất qua .data()sẽ trả về một Objecttrong khi truy xuất qua .attr()sẽ trả về một chuỗi. Xem ví dụ jsfiddle.

.data()quá trình xử lý bổ sung jQuery lưu trữ kết quả đánh giá thuộc tính $.cache- xét cho cùng, sau khi một thuộc tính dữ liệu đã được đánh giá, sẽ rất lãng phí nếu đánh giá lại mỗi lần .data()gọi - đặc biệt là vì các biến dữ liệu có thể chứa các chuỗi JSON phức tạp.

Tôi đã nói tất cả những điều đó để nói như sau: Sau khi truy xuất một thuộc tính thông qua .data()bất kỳ thay đổi nào được thực hiện bởi .attr('data-myvar', '')sẽ không được nhìn thấy bởi các .data()cuộc gọi tiếp theo . Kiểm tra điều này trên jsfiddle.

Để tránh vấn đề này, đừng xen kẽ .data.attr()cuộc gọi. Sử dụng cái này hay cái kia.


đánh dấu đây là câu trả lời. vui lòng xem bài kiểm tra này để biết tất cả các trường hợp có thể xảy ra với .data () so với .attr (), bao gồm nhận & thiết lập bằng cách sử dụng từng và xuất độ dài của các bộ chọn sau khi chúng đã được đặt, jsbin.com/acegef/edit# javascript, html, live
Ian Davis

9
Ít nhất điều này giải thích hành vi dường như không trực quan ... mặc dù điều này có thể gây ra một số đau đầu nhỏ hơn khi một người sử dụng thư viện của bên thứ ba, một số trong số họ chỉ sử dụng dữ liệu () và những người khác thay đổi thuộc tính thực tế.
Haroldo_OK

1
@leepowers, "Sau khi truy xuất thuộc tính qua .data (), bất kỳ thay đổi nào được thực hiện bởi .attr ('data-myvar', '') sẽ không được nhìn thấy bởi các lệnh gọi .data () tiếp theo", nếu đó thực sự là do bộ nhớ đệm ( $ .cache), thì có vẻ như không ổn! thay vì dựa một cách mù quáng vào bộ nhớ cache, .data tiếp theo () cuộc gọi có thể làm một số kiểm tra cơ bản () như thế cho dù giá trị rỗng ngay bây giờ hoặc dài chuỗi thay đổi (phù hợp với bộ nhớ cache với giá trị hiện tại)
minhajul

1
Cần lưu ý rằng cố gắng thiết lập dữ liệu ('id', val) cũng không thành công nếu giá trị không được truy xuất trước đó ... thiết kế tuyệt vời của hàm data () bởi Jquery.
andreszs

3
Vì vậy, đó là bộ nhớ cache dữ liệu () đang giữ tôi hàng giờ. Hèn chi tại sao dù tôi có thay đổi giá trị của nó bao nhiêu thì nó vẫn trả về giá trị như cũ. Cảm ơn vì điều đó.
Lynnell Emmanuel Neri

17

Đây là kết quả của sự hiểu lầm: dataKHÔNG phải là một trình truy cập cho data-*các thuộc tính . Nó vừa nhiều hơn vừa ít hơn thế.

datalà một bộ truy cập cho bộ nhớ cache dữ liệu của jQuery trên phần tử. Bộ nhớ đệm đó được khởi tạo từ data-*các thuộc tính nếu có bất kỳ thuộc tính nào, nhưng datakhông bao giờ ghi vào các thuộc tính, cũng như việc thay đổi thuộc tính không làm thay đổi bộ đệm dữ liệu sau khi khởi tạo:

const div = $("[data-example]");
console.log('div.data("example"):', div.data("example"));
console.log('div.attr("data-example"):', div.attr("data-example"));
console.log('Using div.data("example", "updated")');
div.data("example", "updated");
console.log('div.data("example"):', div.data("example"));
console.log('div.attr("data-example"):', div.attr("data-example"));
<div data-example="initial value"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

datacũng xoa bóp những gì nó tìm thấy theo nhiều cách khác nhau, đoán các kiểu dữ liệu, thực hiện data("answer")trên một phần tử bằng data-answer="42"số, không phải chuỗi hoặc thậm chí phân tích cú pháp mọi thứ dưới dạng JSON nếu chúng giống JSON:

console.log(typeof $("[data-answer]").data("answer"));
console.log(typeof $("[data-json]").data("json"));
console.log(typeof $("[data-str]").data("str"));
<div data-answer="42"></div>
<div data-json='{"answer":42}'></div>
<div data-str="example"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Nếu bạn muốn sử dụng các thuộc tính (cả đọc và thiết lập chúng), hãy sử dụng attr, không data. attr một người truy cập cho các thuộc tính.


6

Đó là bởi vì tên của thuộc tính là data-itemname. Bạn không thể sử dụng -trong ký obj.attributehiệu viết tắt (obj.data-itemname sẽ được hiểu là "obj.data trừ tên item").


Nói ai? bạn có thể cung cấp một liên kết?
jahrichie

6

.attr("data-itemname", "someValue") sửa đổi DOM.

.data("itemname", "someValue") sửa đổi bộ đệm jQuery.

Để điều này hoạt động theo Javascript và thêm vào CSS, bạn phải đặt cả hai.

theaterA.find(".someLink").attr("data-itemname", "someValue");
theaterA.find(".someLink").data("itemname", "someValue");

4

Tại sao bạn không chỉ sử dụng .data()ở mọi nơi?

Bạn cũng có thể khai báo nội tuyến các giá trị mặc định trên HTML, điều này cũng tốt.

<span data-code="pony">text</span>

$("span").data("code") == "pony" // true

nếu bạn muốn thay đổi nó, bạn chỉ cần làm

$("span").data("code", "not-a-pony");

và để xóa nó hoàn toàn, bạn có thể gọi

$("span").removeData("code");

bạn thực sự nên thử và tránh sử dụng .attr("data-*"), tôi không biết tại sao bạn lại muốn làm như vậy.


s / nên / phải, sử dụng .attr('data-*', ...)sẽ không làm cho các dữ liệu có thể nhìn thấy.data()
ThiefMaster

Nhưng không phải làm điều đó với attr () theo cách bạn phải làm mà không có jQuery? (với getAttribute tho)
powerbuoy

Nếu bạn không có jQuery mà bạn sử dụng getAttribute()setAttribute()- vì vậy cả hai phương pháp sẽ truy cập vào các thuộc tính thực và nó sẽ hoạt động trở lại. Hoặc bạn chỉ sử dụng thuộc dataSettính mà các trình duyệt hiện đại cung cấp.
ThiefMaster

1
Đừng chọn các phần tử như vậy. Nó không hiệu quả một cách khủng khiếp vì nó sẽ phải lặp lại mọi phần tử trong tài liệu. Sử dụng classthay thế vì trình duyệt có các hàm gốc để lấy các phần tử với một lớp nhất định.
ThiefMaster

1
nhưng, "555" là dữ liệu, vì vậy tôi nên sử dụng logic data (). đặt dữ liệu đó trong tên lớp là trộn dữ liệu với bản trình bày. tôi cho là cách làm khác.
Ian Davis

1

Bạn phải đặt dữ liệu bằng cách sử dụng .data('itemname', 'someValue');. Sử dụng .attr()để đặt thuộc tính dữ liệu sẽ không hoạt động: http://jsfiddle.net/ThiefMaster/YHsKx/

Tuy nhiên, bạn có thể cung cấp các giá trị nội dòng bằng cách sử dụng ví dụ: <div data-key="value">trong đánh dấu.


trong jsfiddle, get hoạt động sau khi bạn thực hiện cả hai bộ. vì vậy, thực hiện attr ("data-itemname", "value") KHÔNG hoạt động. Tôi đang sử dụng Chrome.
Ian Davis

@Ian uh, không. lệnh .data()gọi đặt thuộc tính, trong khi lệnh .attr()gọi không làm gì cả.
bevacqua

@IanDavis: Nhấp vào "set attr" và "get" sẽ cung cấp cho bạn một đối tượng trống. Chỉ "thiết lập dữ liệu" hoạt động.
ThiefMaster

@Nico - đây chính xác là những gì tôi đã làm: (1) nhấp vào nút "set attr", sau đó (2) nhấp vào nút "get". đây là những gì đã xảy ra: nó đã cảnh báo tôi, "{" test ":" meo "}". vì vậy, .attr () đặt thuộc tính. nếu không, cảnh báo sẽ trống. Nếu bạn làm theo các bước chính xác đó, bạn có nhận được kết quả khác không? cảm ơn.
Ian Davis

1
@ThiefMaster - trong rạp hát Một trong mã được cung cấp của tôi, tôi không sử dụng .attr()chút nào, chỉ .data()và, độ dài của bộ chọn, $(".someLink[data-tofilllater='theater5link']")bằng 0. vì vậy nó giống như tôi phải sử dụng .attr(): /
Ian Davis

0

Tôi có thể thấy rằng điều này đã đưa ra một số phân chia về cách tiếp cận cài đặt thuộc tính dữ liệu.

Tôi cũng gặp phải vấn đề này và tôi thấy rằng vấn đề dường như chỉ đơn giản là định dạng tên thuộc tính dữ liệu .

Theo kinh nghiệm của tôi, bạn nên tránh sử dụng dấu gạch nối trong biến dữ liệu (tên biến đứng sau " data- ").

Điều này không hiệu quả với tôi:

[Đánh dấu]

<div class="list" id="myElement1" data-item-order="some-value"> .... </div>

[jQuery]

jQuery("#myElement1").data("item-order", "my-new-value");

Nhưng những điều sau đây hoạt động tốt! :):

(Tôi sử dụng dấu gạch dưới thay vì dấu gạch nối khi được yêu cầu)

[Đánh dấu]

<div class="list" id="myElement1" data-item_order="some-value"> .... </div>

[jQuery]

jQuery("#myElement1").data("item_order", "my-new-value");

Tôi hy vọng nó sẽ giúp. Chúc mừng mọi người!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.