jQuery .data () ไม่ทำงาน แต่ .attr () ทำ


107

ยกโทษให้ฉันที่ไม่เจาะจงเรื่องนี้มากขึ้น ฉันมีข้อผิดพลาดแปลก ๆ หลังจากโหลดเอกสารแล้วฉันก็วนองค์ประกอบบางอย่างที่มีอยู่เดิมdata-itemname=""และตั้งค่าเหล่านั้นโดยใช้.attr("data-itemname", "someValue").

ปัญหา: เมื่อฉันห่วงภายหลังผ่านองค์ประกอบเหล่านั้นถ้าฉันทำelem.data().itemnameฉันได้รับ""แต่ถ้าฉันทำฉันได้รับelem.attr("data-itemname") "someValue"เหมือนกับ.data()getter ของ jQuery รับเฉพาะองค์ประกอบที่ตั้งค่าไว้ในตอนแรกเพื่อให้มีค่าบางอย่าง แต่ถ้าเดิมว่างเปล่าและตั้งค่าในภายหลัง.data()จะไม่ได้รับค่าในภายหลัง

ฉันพยายามสร้างจุดบกพร่องนี้ขึ้นใหม่ แต่ไม่สามารถทำได้

แก้ไข

ฉันได้สร้างจุดบกพร่องขึ้นใหม่แล้ว! http://jsbin.com/ihuhep/edit#javascript,html,live

นอกจากนี้ตัวอย่างจากลิงค์ด้านบน ...

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
พยายามสร้างข้อผิดพลาดขึ้นใหม่ :-)
dkamins

1
มันไม่ได้เป็นelem.data("itemname")ไม่ได้elem.data().itemname?
Hogan

ในขณะที่ elem.data (). itemname จะให้คุณอ่านค่าซึ่งจะไม่อนุญาตให้คุณกำหนดค่า (ดังนั้นจึงelem.data().itemname = somevalue;ไม่เปลี่ยนแปลงข้อมูลพื้นฐาน)
Hogan

@dkamins - ฉันได้สร้างบั๊กขึ้นใหม่โปรดดูเวอร์ชันที่แก้ไข
Ian Davis

คำตอบ:


211

ฉันพบ "ข้อบกพร่อง" ที่คล้ายกันเมื่อสองสามวันก่อนเมื่อทำงานกับ.data()และ.attr('data-name')สำหรับแอตทริบิวต์ข้อมูล HTML5

พฤติกรรมที่คุณกำลังอธิบายไม่ใช่ข้อบกพร่อง แต่เกิดจากการออกแบบ

การ.data()เรียกเป็นแบบพิเศษ - ไม่เพียง แต่ดึงข้อมูลแอตทริบิวต์ข้อมูล HTML5 เท่านั้น แต่ยังพยายามประเมิน / แยกวิเคราะห์แอตทริบิวต์ ดังนั้นด้วยแอตทริบิวต์เช่นdata-myjson='{"hello":"world"}'เมื่อดึงข้อมูลผ่าน.data()จะส่งคืนObjectwhile เรียกข้อมูลผ่าน.attr()จะส่งคืนสตริง ดูตัวอย่าง jsfiddle

เนื่องจาก.data()การประมวลผลเพิ่มเติม jQuery จะเก็บผลลัพธ์ของการประเมินแอตทริบิวต์ไว้ใน$.cacheภายหลังเมื่อมีการประเมินแอตทริบิวต์ข้อมูลแล้วการประเมินซ้ำทุกครั้งจะเป็นการสิ้นเปลือง.data()โดยเฉพาะอย่างยิ่งเนื่องจากตัวแปรข้อมูลสามารถมีสตริง JSON ที่ซับซ้อนได้

ฉันพูดทั้งหมดที่จะพูดต่อไปนี้: หลังจากดึงแอตทริบิวต์ผ่าน.data()การเปลี่ยนแปลงใด ๆ ที่เกิดขึ้น.attr('data-myvar', '')จะไม่ปรากฏให้เห็นในการ.data()โทรครั้งต่อไป ทดสอบสิ่งนี้บน jsfiddle

เพื่อหลีกเลี่ยงปัญหานี้อย่าพูดแทรก.dataและ.attr()โทร ใช้อย่างใดอย่างหนึ่ง


ทำเครื่องหมายว่าเป็นคำตอบ โปรดดูการทดสอบนี้สำหรับสถานการณ์ที่เป็นไปได้ทั้งหมดด้วย. data () เทียบกับ .attr () ซึ่งรวมถึงการรับและการตั้งค่าโดยใช้แต่ละรายการและแสดงความยาวของตัวเลือกหลังจากที่ตั้งค่าแล้วjsbin.com/acegef/edit# javascript, html, ถ่ายทอดสด
Ian Davis

9
อย่างน้อยสิ่งนี้ก็อธิบายถึงพฤติกรรมที่ไม่ใช้งานง่ายอย่างเห็นได้ชัด ... แม้ว่าสิ่งนี้อาจทำให้เกิดอาการปวดหัวเล็กน้อยเมื่อใช้ไลบรารีของบุคคลที่สามบางส่วนใช้เฉพาะ data () และอื่น ๆ เปลี่ยนแอตทริบิวต์จริง
Haroldo_OK

1
@leepowers "หลังจากดึงแอตทริบิวต์ผ่าน. data () การเปลี่ยนแปลงใด ๆ ที่ทำโดย .attr ('data-myvar', '') จะไม่เห็นโดยการเรียก. data () ที่ตามมา" หากเป็นเช่นนั้นจริง ๆ ของแคช ( $ .cache) ดูเหมือนจะไม่ดี! แทนที่จะใช้แคชสุ่มสี่สุ่มห้าการเรียก. data () ที่ตามมาสามารถทำการตรวจสอบขั้นพื้นฐานบางอย่าง () เช่นว่าค่าว่างตอนนี้หรือความยาวสตริงเปลี่ยนไปหรือไม่ (จับคู่แคชกับค่าปัจจุบัน)
minhajul

1
ควรสังเกตว่าการพยายามตั้งค่าข้อมูล ('id', val) จะล้มเหลวเช่นกันหากไม่ได้รับค่าก่อนหน้านี้ ... การออกแบบฟังก์ชัน data () ที่ยอดเยี่ยมโดย Jquery
andreszs

3
ดังนั้นมันคือแคช data () ที่กักขังฉันไว้หลายชั่วโมง ไม่แปลกใจเลยว่าทำไมไม่ว่าฉันจะเปลี่ยนค่าไปเท่าไหร่มันก็ยังคืนค่าเหมือนเดิม ขอบคุณสำหรับสิ่งนี้.
Lynnell Emmanuel Neri

17

นี้เป็นผลจากความเข้าใจผิดนี้dataไม่ได้เป็นเข้าถึงสำหรับdata-*แอตทริบิวต์ มันทั้งมากและน้อยกว่านั้น

dataเป็นตัวเข้าถึงแคชข้อมูลของ jQuery ในองค์ประกอบ แคชนั้นถูกเตรียมใช้งานจากdata-*แอ็ตทริบิวต์หากมีอยู่ แต่dataไม่เคยเขียนไปยังแอ็ตทริบิวต์และไม่เปลี่ยนแอ็ตทริบิวต์เปลี่ยนแคชข้อมูลหลังจากการกำหนดค่าเริ่มต้น:

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>

dataนอกจากนี้ยังนวดสิ่งที่พบในรูปแบบต่างๆคาดเดาประเภทข้อมูลสร้างdata("answer")องค์ประกอบด้วยdata-answer="42"ตัวเลขไม่ใช่สตริงหรือแม้แต่แยกวิเคราะห์สิ่งต่างๆเป็น JSON หากมีลักษณะเหมือน 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>

หากคุณต้องการใช้แอตทริบิวต์ (ทั้งการอ่านและการตั้งค่าพวกเขา) ใช้งานไม่ได้attr เป็นตัวเข้าถึงแอตทริบิวต์dataattr


7

.attr("data-itemname", "someValue") ปรับเปลี่ยน DOM

.data("itemname", "someValue") แก้ไขแคช jQuery

เพื่อให้สิ่งนี้ทำงานใน Javascript และนอกเหนือจาก CSS คุณต้องตั้งค่าทั้งสองอย่าง

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

6

data-itemnameนั่นเป็นเพราะชื่อแอตทริบิวต์คือ คุณไม่สามารถใช้-ในobj.attributeสัญกรณ์ชวเลขได้(obj.data-itemname จะถูกแปลเป็น "obj.data minus itemname")


บอกว่าใคร? คุณสามารถให้ลิงค์ได้หรือไม่?
jahrichie

4

ทำไมคุณไม่ใช้.data()ทุกที่

คุณยังสามารถประกาศค่าเริ่มต้นแบบอินไลน์บน HTML ซึ่งก็ใช้ได้เช่นกัน

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

และ

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

หากคุณต้องการเปลี่ยนแปลงคุณก็ทำ

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

และหากต้องการลบออกทั้งหมดคุณสามารถเรียกใช้

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

คุณควรพยายามหลีกเลี่ยงการใช้จริงๆ.attr("data-*")ฉันไม่รู้ว่าทำไมคุณถึงต้องการทำเช่นนั้นต่อไป


s / should / must การใช้.attr('data-*', ...)จะไม่ทำให้ข้อมูลปรากฏแก่.data()
ThiefMaster

แต่ไม่ได้ทำด้วย attr () แบบที่คุณต้องทำโดยไม่มี jQuery? (พร้อม getAttribute tho)
powerbuoy

หากคุณไม่มี jQuery ที่คุณใช้getAttribute()และsetAttribute()- ดังนั้นทั้งสองวิธีจะเข้าถึงแอตทริบิวต์จริงและจะใช้งานได้อีกครั้ง หรือคุณเพียงแค่ใช้dataSetคุณสมบัติที่ทันสมัยเบราว์เซอร์ให้
ThiefMaster

1
อย่าเลือกองค์ประกอบแบบนั้น มันไม่มีประสิทธิภาพอย่างมากเนื่องจากจะต้องวนซ้ำทุกองค์ประกอบในเอกสาร ใช้classแทนเนื่องจากเบราว์เซอร์มีฟังก์ชันดั้งเดิมเพื่อรับองค์ประกอบที่มีคลาสหนึ่ง ๆ
ThiefMaster

1
แต่ "555" เป็นข้อมูลดังนั้นฉันควรใช้ตรรกะ data () การใส่ข้อมูลนั้นในชื่อคลาสเป็นการผสมข้อมูลกับการนำเสนอ ฉันคิดว่าวิธีที่แตกต่างกันในการทำ
Ian Davis

1

คุณต้องตั้งค่าข้อมูลโดยใช้.data('itemname', 'someValue');. การใช้.attr()เพื่อตั้งค่าแอตทริบิวต์ข้อมูลจะไม่ทำงาน: http://jsfiddle.net/ThiefMaster/YHsKx/

อย่างไรก็ตามคุณสามารถระบุค่าแบบอินไลน์ได้โดยใช้เช่น<div data-key="value">ในมาร์กอัป


ใน jsfiddle รับผลงานหลังจากที่คุณทำทั้งสองชุด ดังนั้นการทำ attr ("data-itemname", "value") จึงได้ผล ฉันใช้ Chrome
Ian Davis

@ เอียนเอ่อไม่นะ การ.data()โทรตั้งค่าแอตทริบิวต์ในขณะที่การ.attr()โทรไม่ทำอะไรเลย
bevacqua

@IanDavis: คลิก "set attr" และ "get" จะทำให้คุณมีวัตถุว่างเปล่า "ข้อมูลชุด" เท่านั้นที่ใช้งานได้
ThiefMaster

@Nico - นี่คือสิ่งที่ฉันทำ: (1) คลิกปุ่ม "set attr" จากนั้น (2) คลิกปุ่ม "get" นี่คือสิ่งที่เกิดขึ้นมันแจ้งเตือนฉัน "{" test ":" meow "}" ดังนั้น .attr () จึงตั้งค่าแอตทริบิวต์ มิฉะนั้นการแจ้งเตือนจะว่างเปล่า หากคุณทำตามขั้นตอนเหล่านั้นคุณจะได้ผลลัพธ์ที่แตกต่างกันหรือไม่? ขอบคุณ.
Ian Davis

1
@ThiefMaster - ในโรงละครในรหัสที่ฉันให้มาฉันไม่ได้ใช้.attr()เลยเพียงอย่างเดียว.data()และความยาวของตัวเลือก$(".someLink[data-tofilllater='theater5link']")เป็นศูนย์ ดังนั้นฉันจึงต้องใช้.attr(): /
Ian Davis

0

ฉันเห็นว่าสิ่งนี้ทำให้เกิดการแบ่งส่วนวิธีการตั้งค่าแอตทริบิวต์ข้อมูล

ผมทำงานเกินไปในปัญหานี้และผมพบว่าปัญหาที่ดูเหมือนจะเป็นเพียงแค่ชื่อแอตทริบิวต์การจัดรูปแบบข้อมูล

จากประสบการณ์ของฉันคุณควรหลีกเลี่ยงการใช้ยัติภังค์ในตัวแปรข้อมูล (ชื่อตัวแปรที่อยู่หลัง " data- ")

สิ่งนี้ไม่ได้ผลสำหรับฉัน:

[มาร์กอัป]

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

[jQuery]

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

แต่ต่อไปนี้ใช้งานได้ดี! :):

(ฉันใช้ขีดล่างแทนยัติภังค์เมื่อจำเป็น)

[มาร์กอัป]

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

[jQuery]

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

ฉันหวังว่ามันจะช่วยได้ ไชโยทุกคน!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.