ตัวเลือกข้อมูล jquery


184

ฉันต้องเลือกองค์ประกอบตามค่าที่เก็บไว้ใน.data()วัตถุขององค์ประกอบ อย่างน้อยที่สุดฉันต้องการเลือกคุณสมบัติข้อมูลระดับสูงสุดโดยใช้ตัวเลือกอาจเป็นดังนี้:

$('a').data("category","music");
$('a:data(category=music)');

หรือบางทีตัวเลือกจะอยู่ในรูปแบบตัวเลือกแอตทริบิวต์ปกติ:

$('a[category=music]');

หรือในรูปแบบของแอตทริบิวต์ แต่มีตัวระบุเพื่อระบุว่าอยู่ใน.data():

$('a[:category=music]');

ฉันพบว่าการใช้งานของ James Padolseyดูเรียบง่าย แต่ก็ดี รูปแบบตัวเลือกด้านบนวิธีการมิเรอร์ที่แสดงในหน้านั้น นอกจากนี้ยังมีแพทช์ Sizzleนี้

ด้วยเหตุผลบางอย่างฉันจำได้ว่าได้อ่านมาพักหนึ่งแล้วว่า jQuery 1.4 จะรวมการสนับสนุน selector สำหรับค่าใน.data()วัตถุjquery อย่างไรก็ตามตอนนี้ฉันกำลังหามันฉันไม่สามารถหามันได้ อาจเป็นเพียงคำขอคุณลักษณะที่ฉันเห็น มีการสนับสนุนสำหรับสิ่งนี้และฉันแค่ไม่เห็นมันใช่ไหม

โดยอุดมคติแล้วฉันต้องการสนับสนุนคุณสมบัติย่อยใน data () โดยใช้เครื่องหมายจุด แบบนี้:

$('a').data("user",{name: {first:"Tom",last:"Smith"},username: "tomsmith"});
$('a[:user.name.first=Tom]');

ฉันยังต้องการสนับสนุนตัวเลือกข้อมูลหลายตัวที่พบเฉพาะองค์ประกอบที่มีตัวเลือกข้อมูลทั้งหมดที่ระบุเท่านั้น jquery หลายตัวเลือกปกติจะเป็นการดำเนินการหรือ ตัวอย่างเช่น$('a.big, a.small')เลือกaแท็กที่มีคลาสbigหรือsmall) ฉันกำลังมองหาและอาจเป็นเช่นนี้:

$('a').data("artist",{id: 3281, name: "Madonna"});
$('a').data("category","music");
$('a[:category=music && :artist.name=Madonna]');

ท้ายสุดมันจะดีถ้าตัวดำเนินการเปรียบเทียบและคุณสมบัติ regex พร้อมใช้งานบนตัวเลือกข้อมูล ดังนั้น$(a[:artist.id>5000])จะเป็นไปได้ ฉันรู้ว่าฉันอาจจะใช้สิ่งนี้ได้filter()มาก แต่ก็ดีถ้ามีรูปแบบตัวเลือกที่เรียบง่าย

มีวิธีแก้ไขปัญหาอะไรให้ทำเช่นนี้ เวลานี้ Padolsey ของ Jame เป็นทางออกที่ดีที่สุดหรือไม่? ข้อกังวลของฉันนั้นเกี่ยวกับประสิทธิภาพเป็นหลัก แต่ก็รวมถึงคุณสมบัติพิเศษเช่นสัญกรณ์ดอทพร็อพเพอร์ตี้ย่อยและตัวเลือกข้อมูลหลายตัว มีการใช้งานอื่น ๆ ที่สนับสนุนสิ่งเหล่านี้หรือดีกว่าในบางวิธี?


ใช้ jquery ui core api.jqueryui.com/category/ui-core มันมี: data () selector
regisbsb

คำตอบ:


101

ฉันได้สร้างdataตัวเลือกใหม่ที่จะช่วยให้คุณสามารถทำการสอบถามซ้อนและเงื่อนไข การใช้งาน:

$('a:data(category==music,artist.name==Madonna)');

รูปแบบคือ:

:data( {namespace} [{operator} {check}]  )

"ผู้ประกอบการ" และ "ตรวจสอบ" เป็นตัวเลือก ดังนั้นถ้าคุณมีเพียง:data(a.b.c)มันก็จะตรวจสอบtruthinessa.b.cของ

คุณสามารถดูโอเปอเรเตอร์ที่มีอยู่ในรหัสด้านล่าง ในหมู่พวกเขาคือ~=สิ่งที่ช่วยให้การทดสอบ regex:

$('a:data(category~=^mus..$,artist.name~=^M.+a$)');

ฉันได้ทดสอบกับรูปแบบต่าง ๆ และดูเหมือนว่าจะทำงานได้ค่อนข้างดี ฉันจะเพิ่มนี่เป็น repo Github เร็ว ๆ นี้ (พร้อมชุดทดสอบเต็มรูปแบบ) ดังนั้นโปรดระวัง!

รหัส:

(function(){

    var matcher = /\s*(?:((?:(?:\\\.|[^.,])+\.?)+)\s*([!~><=]=|[><])\s*("|')?((?:\\\3|.)*?)\3|(.+?))\s*(?:,|$)/g;

    function resolve(element, data) {

        data = data.match(/(?:\\\.|[^.])+(?=\.|$)/g);

        var cur = jQuery.data(element)[data.shift()];

        while (cur && data[0]) {
            cur = cur[data.shift()];
        }

        return cur || undefined;

    }

    jQuery.expr[':'].data = function(el, i, match) {

        matcher.lastIndex = 0;

        var expr = match[3],
            m,
            check, val,
            allMatch = null,
            foundMatch = false;

        while (m = matcher.exec(expr)) {

            check = m[4];
            val = resolve(el, m[1] || m[5]);

            switch (m[2]) {
                case '==': foundMatch = val == check; break;
                case '!=': foundMatch = val != check; break;
                case '<=': foundMatch = val <= check; break;
                case '>=': foundMatch = val >= check; break;
                case '~=': foundMatch = RegExp(check).test(val); break;
                case '>': foundMatch = val > check; break;
                case '<': foundMatch = val < check; break;
                default: if (m[5]) foundMatch = !!val;
            }

            allMatch = allMatch === null ? foundMatch : allMatch && foundMatch;

        }

        return allMatch;

    };

}());

@JP: น่ารักมากฉันรู้ว่าฉันจะไว้ใจคุณ! มุ่งหน้าเข้านอนตอนนี้ แต่ฉันจะลองในวันพรุ่งนี้ เป็นไปได้ที่จะทำหรือดำเนินการเช่นกัน? ฉันไม่ต้องการมันแค่อยากรู้อยากเห็น
Tauren

1
@JP: นอกจากนี้ฉันอยากรู้อยากเห็นของคุณเกี่ยวกับวิธีการเลือกข้อมูลอื่น ๆ ข้อดี / ข้อเสียสำหรับคุณกับพวกเขา ยกตัวอย่างเช่นปลั๊กอินนี้: plugins.jquery.com/project/dataSelector
Tauren

1
มันเป็นไปได้ที่จะทำหรือการดำเนินการ แต่มันอาจจะดีที่สุดที่จะมีสองตัวเลือก$("a:data(condition),a:data(orCondition)")... มันจะมีผลเหมือนกัน ยิ่งคุณเพิ่มคุณสมบัติมากเท่าไหร่ก็ยิ่งช้าเท่านั้น $(foo).filter(function(){...})ถ้าตรรกะที่ซับซ้อนแล้วใช้
James

3
@JP: คุณเคยเปลี่ยนสิ่งนี้เป็นโครงการ Github หรือไม่? ฉันกำลังทำการทดสอบโดยใช้ jQuery 1.5.1 โดยใช้ตัวเลือก $ ("อินพุต: data (ทดสอบ> 400)") บนอินพุตด้วยแอตทริบิวต์ html5 data-test = "500" แต่ตัวเลือกกลับไม่ได้อะไรเลย
James South

1
@JamesSouth นั่นเป็นเพราะตัวเลือกในคำตอบนี้ใช้ระดับต่ำjQuery.dataซึ่งไม่ได้รับข้อมูลที่กำหนดในแอตทริบิวต์ HTML5 หากคุณต้องการการทำงานที่คุณสามารถเปลี่ยนjQuery.dataไป$('selector').dataแต่ที่ปิดการค้าสำหรับความเร็ว
Shef

175

ในขณะนี้ฉันกำลังเลือกสิ่งนี้:

$('a[data-attribute=true]')

ซึ่งดูเหมือนว่าจะใช้งานได้ดี แต่มันจะดีถ้า jQuery สามารถเลือกโดยคุณลักษณะนั้นโดยไม่มีคำนำหน้า 'data-'

ฉันไม่ได้ทดสอบสิ่งนี้กับข้อมูลที่เพิ่มลงในองค์ประกอบผ่าน jQuery แบบไดนามิกดังนั้นอาจเป็นความหายนะของวิธีนี้


นี่คือสิ่งที่ฉันกำลังมองหา หวาน
MikeMurko

109
วิธีนี้ใช้ไม่ได้หากคุณแนบ / แก้ไขข้อมูลผ่าน JS ผ่านฟังก์ชั่น. data () ตัวเลือกคุณสมบัติจะตรวจสอบ DOM, JS stores .data () ในหน่วยความจำเท่านั้น
Clarence Liu

1
คุณช่วยบอกได้ไหมว่าคุณเข้าถึงโดยใช้แอตทริบิวต์ได้อย่างไรถ้าคุณแนบผ่าน. data ()
Maxim V. Pavlov

1
ฉันขอแนะนำให้คำตอบอื่น ๆ ที่ให้ไว้ในหัวข้อนี้เป็นตัวเลือกที่ดีกว่าสำหรับสิ่งอื่นนอกเหนือจากกรณีการใช้งานง่าย
Ash

วิธีแก้ปัญหาของ Dmitri นั้นดูดีสำหรับฉันเพราะมันไม่ได้ใช้รหัสบุคคลที่สาม
Ash

83

คุณยังสามารถใช้ฟังก์ชั่นการกรองอย่างง่ายโดยไม่ต้องใช้ปลั๊กอินใด ๆ นี่ไม่ใช่สิ่งที่คุณต้องการ แต่ผลลัพธ์เหมือนกัน:

$('a').data("user", {name: {first:"Tom",last:"Smith"},username: "tomsmith"});

$('a').filter(function() {
    return $(this).data('user') && $(this).data('user').name.first === "Tom";
});

2
นี่เป็นความคิดที่ดีฉันลืมfilterฟังก์ชั่นการสำรวจเส้นทางที่สามารถรับฟังก์ชั่นทดสอบ =) ขอบคุณ
Clarence Liu

ฉันจะทำอย่างไรกับ "แทนที่" แทนที่จะเท่ากับทอมได้อย่างไร
Alisso

1
Alisso แทน name.first == "Tom" ใช้ name.first && name.first.indexOF ("Tom")> -1;
Dmitri

24

ฉันต้องการเตือนคุณว่า$('a[data-attribute=true]')ไม่ทำงานตามคำตอบของแอชลีย์ถ้าคุณแนบข้อมูลไปยังองค์ประกอบ DOM ผ่านฟังก์ชั่น data ()

ใช้งานได้ตามที่คุณคาดหวังหากคุณเพิ่ม data-attr จริงใน HTML ของคุณ แต่ jQuery เก็บข้อมูลไว้ในหน่วยความจำดังนั้นผลลัพธ์ที่คุณได้รับ$('a[data-attribute=true]')จะไม่ถูกต้อง

คุณจะต้องใช้ปลั๊กอินข้อมูลhttp://code.google.com/p/jquerypluginsblog/ใช้filterโซลูชันของ Dmitri หรือทำ $ .each ตามองค์ประกอบทั้งหมดและตรวจสอบ. data () ซ้ำ ๆ


ในกรณีของฉันมันไม่เป็นไรเพราะฉันเติมข้อมูลฟิลด์ไว้ที่ฝั่งเซิร์ฟเวอร์ล่วงหน้าและจะต้องปรึกษาด้วยวิธีนี้ในการโหลดครั้งแรก ตัวกรองอาจจะเร็วเหมือนกัน (แต่ละตัวจะช้ากว่านี้อย่างแน่นอน) แต่สิ่งนี้จะชนะเมื่ออ่านได้
อย่า

11

มี:data()ปลั๊กอินตัวกรองที่ทำสิ่งนี้ :)

ตัวอย่างจากคำถามของคุณ:

$('a:data("category=music")')
$('a:data("user.name.first=Tom")');
$('a:data("category=music"):data("artist.name=Madonna")');
//jQuery supports multiple of any selector to restrict further, 
//just chain with no space in-between for this effect

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

ตัวเลือกการเปรียบเทียบที่คุณกล่าวถึงจะทำได้ดีที่สุดใน a .filter()ไม่มีการสนับสนุนในตัวในปลั๊กอินแม้ว่าคุณสามารถเพิ่มได้โดยไม่มีปัญหา


ขอบคุณสำหรับคำตอบอย่างละเอียด คุณรู้หรือไม่ว่าการใช้data-*คุณสมบัติHTML5 และการเลือกจะเร็วกว่าการเลือก.data()คุณสมบัติ? นอกจากนี้ยังมีแนวคิดใดบ้างที่ฉันสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับแคช $ ._ ได้ ฉัน googled มัน แต่ไม่พบมาก
Tauren

@Tauren - ความผิดของฉัน$.cacheไม่ใช่$._cacheคุณสามารถดูวิธีการนำไปใช้และใช้ใน jQuery core ได้ที่นี่: github.com/jquery/jquery/blob/master/src/data.js#L4 เมื่อคุณเรียก.data()มันว่าจริง ๆ แล้วการจัดเก็บเป็นวัตถุ ใน$.cache[elementUniqueID]ซึ่งเป็นรหัสที่ได้รับมอบหมายตามความจำเป็นในทางที่ไม่เป็นอันตรายต่อแต่ละองค์ประกอบเช่น 1, 2, 3, ฯลฯ รหัสการปีนเขาจะถูกเปิดเผยใน jQuery 1.4.3 ฉันเชื่อว่าอิงตามความเห็นคอมไพล์ในวันอื่น ๆ ฉันจะสมมติว่าเส้นทาง HTML 5 จะเร็วขึ้นขึ้นอยู่กับการเพิ่มประสิทธิภาพเบราว์เซอร์ที่มีอยู่ (ฉันแน่ใจว่าจะมีอีกมาก)
Nick Craver

7

คุณสามารถตั้งค่า data-*ททริบิวให้กับ Elm โดยใช้attr()แล้วเลือกใช้แอททริบิวนั้น:

var elm = $('a').attr('data-test',123); //assign 123 using attr()
elm = $("a[data-test=123]"); //select elm using attribute

และตอนนี้สำหรับ Elm นั้นทั้งสองattr()และdata()จะให้ผล123 :

console.log(elm.attr('data-test')); //123
console.log(elm.data('test')); //123

แต่ถ้าคุณปรับเปลี่ยนค่าเป็น456ใช้attr(), data() จะยังคงเป็น123 :

elm.attr('data-test',456); //modify to 456
elm = $("a[data-test=456]"); //reselect elm using new 456 attribute

console.log(elm.attr('data-test')); //456
console.log(elm.data('test')); //123

ดังนั้นเมื่อฉันเข้าใจแล้วดูเหมือนว่าคุณควรหลีกเลี่ยงการผสมattr()และdata()คำสั่งในรหัสของคุณหากคุณไม่จำเป็นต้อง เนื่องจากattr()ดูเหมือนว่าจะตรงกับ DOM โดยตรงในขณะที่data()โต้ตอบกับ 'หน่วยความจำ' แม้ว่าค่าเริ่มต้นจะมาจาก DOM แต่ประเด็นสำคัญคือทั้งสองไม่จำเป็นต้องซิงค์กันเลย

ดังนั้นควรระวัง

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

ขอบคุณ @Clarence Liu ถึงคำตอบของ @ Ash รวมถึงโพสต์นี้



5

หากคุณใช้ jQueryUI คุณจะได้:dataตัวเลือกเวอร์ชัน (แบบง่าย) ซึ่งจะตรวจสอบว่ามีรายการข้อมูลอยู่หรือไม่เพื่อให้คุณทำสิ่งที่ต้องการ$("div:data(view)")หรือ$( this ).closest(":data(view)")หรือ

ดูhttp://api.jqueryui.com/data-selector/ ฉันไม่รู้ว่าพวกเขามีมานานแค่ไหน แต่ตอนนี้อยู่ที่นั่นแล้ว!


สิ่งนี้จะตรวจสอบว่ามีรายการข้อมูลเหมือนที่คุณพูดหรือไม่ ไม่ได้ตรวจสอบค่า (ตามเอกสาร) ดีใจที่ได้ทราบเกี่ยวกับเรื่องนี้
Fractalf

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