bộ chọn dữ liệu jquery


184

Tôi cần chọn các phần tử dựa trên các giá trị được lưu trữ trong .data()đối tượng của phần tử . Tối thiểu, tôi muốn chọn các thuộc tính dữ liệu cấp cao nhất bằng cách sử dụng các bộ chọn, có lẽ như thế này:

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

Hoặc có lẽ bộ chọn sẽ ở định dạng bộ chọn thuộc tính thông thường:

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

Hoặc ở định dạng thuộc tính, nhưng với một chỉ định để chỉ ra nó ở trong .data() :

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

Tôi đã tìm thấy triển khai của James Padolsey trông đơn giản nhưng tốt. Các định dạng chọn trên các phương thức nhân bản được hiển thị trên trang đó. Ngoài ra còn có bản vá Sizzle này .

Vì một số lý do, tôi nhớ lại việc đọc một thời gian trước rằng jQuery 1.4 sẽ bao gồm hỗ trợ cho các bộ chọn trên các giá trị trong .data()đối tượng jquery . Tuy nhiên, bây giờ khi tôi đang tìm kiếm nó, tôi không thể tìm thấy nó. Có lẽ nó chỉ là một yêu cầu tính năng mà tôi thấy. Có hỗ trợ cho điều này và tôi chỉ không nhìn thấy nó?

Lý tưởng nhất, tôi muốn hỗ trợ các thuộc tính phụ trong dữ liệu () bằng cách sử dụng ký hiệu dấu chấm. Như thế này:

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

Tôi cũng muốn hỗ trợ nhiều bộ chọn dữ liệu, trong đó chỉ các phần tử có TẤT CẢ các bộ chọn dữ liệu được chỉ định được tìm thấy. Nhiều bộ chọn jquery thông thường thực hiện thao tác OR. Chẳng hạn, $('a.big, a.small')chọn acác thẻ với một trong hai lớp bighoặc small). Tôi đang tìm kiếm một AND, có lẽ như thế này:

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

Cuối cùng, sẽ thật tuyệt nếu các toán tử so sánh và các tính năng regex có sẵn trên các bộ chọn dữ liệu. Vì vậy, $(a[:artist.id>5000])sẽ có thể. Tôi nhận ra rằng tôi có thể có thể làm nhiều việc này bằng cách sử dụng filter(), nhưng thật tuyệt khi có một định dạng chọn đơn giản.

Những giải pháp có sẵn để làm điều này? Jame's Padolsey có phải là giải pháp tốt nhất vào lúc này không? Mối quan tâm của tôi chủ yếu liên quan đến hiệu suất, mà còn ở các tính năng bổ sung như ký hiệu chấm thuộc tính phụ và nhiều bộ chọn dữ liệu. Có những triển khai khác hỗ trợ những điều này hoặc tốt hơn theo một cách nào đó?


Sử dụng jiery ui core api.jqueryui.com/c Category / ui-core Nó có bộ chọn: data ()
regisbsb

Câu trả lời:


101

Tôi đã tạo một databộ chọn mới cho phép bạn thực hiện các điều kiện AND và truy vấn lồng nhau. Sử dụng:

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

Mô hình là:

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

"Toán tử" và "kiểm tra" là tùy chọn. Vì vậy, nếu bạn chỉ có :data(a.b.c)nó sẽ chỉ đơn giản là kiểm tra sự truthiness của a.b.c.

Bạn có thể thấy các toán tử có sẵn trong mã dưới đây. Trong số đó là ~=cho phép thử nghiệm regex:

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

Tôi đã thử nghiệm nó với một vài biến thể và nó dường như hoạt động khá tốt. Có lẽ tôi sẽ thêm phần này dưới dạng repo Github (với bộ kiểm tra đầy đủ), vì vậy hãy chú ý!

Mật mã:

(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: Rất ngọt ngào, tôi biết tôi có thể tin tưởng vào bạn! Bây giờ đi ngủ, nhưng tôi sẽ thử vào ngày mai. Có thể làm hoạt động HOẶC là tốt? Tôi không cần nó, chỉ tò mò thôi.
Tauren

1
@JP: Ngoài ra, tôi tò mò về việc bạn sử dụng các giải pháp chọn dữ liệu khác, ưu / nhược điểm cho bạn so với của họ. Chẳng hạn, plugin này: plugins.jquery.com/project/dataSelector .
Tauren

1
Có thể thực hiện các thao tác HOẶC, nhưng tốt nhất là chỉ cần có hai bộ chọn, $("a:data(condition),a:data(orCondition)")... nó sẽ có tác dụng tương tự. Bạn càng thêm nhiều tính năng, nó sẽ càng chậm. Nếu logic là phức tạp, sau đó sử dụng $(foo).filter(function(){...}).
James

3
@JP: Bạn đã bao giờ biến điều này thành một dự án github chưa? Tôi đang chạy thử nghiệm bằng jQuery 1.5.1 bằng cách sử dụng bộ chọn $ ("input: data (test> 400)") trên một đầu vào với thuộc tính html5 data-test = "500" nhưng bộ chọn không trả về gì.
James South

1
@JamesSouth Đó là vì bộ chọn trong câu trả lời này sử dụng mức thấp jQuery.data, không nhận được dữ liệu được xác định trong các thuộc tính HTML5. Nếu bạn muốn chức năng đó, bạn có thể thay đổi jQuery.datađể $('selector').data, nhưng đó là một thương mại giảm cho tốc độ.
Shef

175

Hiện tại tôi đang chọn như thế này:

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

Điều này dường như chỉ hoạt động tốt, nhưng sẽ rất tuyệt nếu jQuery có thể chọn thuộc tính đó mà không có tiền tố 'data-'.

Tôi đã không kiểm tra điều này với dữ liệu được thêm vào các phần tử thông qua jQuery một cách linh hoạt, vì vậy đó có thể là sự sụp đổ của phương thức này.


Điều này thật đúng với gì mà tôi đã tìm kiếm. Ngọt ngào
MikeMurko

109
Điều này không thực sự hoạt động nếu bạn đính kèm / sửa đổi dữ liệu qua JS thông qua hàm .data (), bộ chọn thuộc tính chỉ kiểm tra DOM, lưu trữ tệp .data () trong bộ nhớ
Clarence Liu

1
Bạn có thể vui lòng cho biết làm thế nào để bạn truy cập theo thuộc tính nếu bạn đính kèm qua .data ()?
Maxim V. Pavlov

1
Tôi đề nghị rằng các câu trả lời khác được cung cấp trong chuỗi này là một lựa chọn tốt hơn cho bất kỳ điều gì khác ngoài trường hợp sử dụng rất đơn giản.
Tro

Giải pháp của Dmitri có vẻ tốt với tôi vì nó không dựa vào mã của bên thứ ba.
Tro

83

Bạn cũng có thể sử dụng chức năng lọc đơn giản mà không cần bất kỳ plugin nào. Đây không phải là chính xác những gì bạn muốn nhưng kết quả là như nhau:

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

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

2
Đây là một ý tưởng tuyệt vời, tôi đã quên filterchức năng truyền tải có thể chấp nhận chức năng kiểm tra =) cảm ơn
Clarence Liu

Làm thế nào tôi có thể làm một "chứa" thay vì bằng với Tom?
Alisso

1
Alisso, thay vì name.first == "Tom" sử dụng name.first && name.first.indexOF ("Tom")> -1;
Dmitri

24

Tôi muốn cảnh báo bạn rằng $('a[data-attribute=true]') nó không hoạt động, theo câu trả lời của Ashley, nếu bạn đã đính kèm dữ liệu vào một phần tử DOM thông qua hàm data ().

Nó hoạt động như bạn mong đợi nếu bạn đã thêm một dữ liệu thực tế trong HTML của mình, nhưng jQuery lưu trữ dữ liệu trong bộ nhớ, do đó, kết quả bạn nhận được $('a[data-attribute=true]')sẽ không chính xác.

Bạn sẽ cần sử dụng plugin dữ liệu http://code.google.com.vn/p/jquerypluginsblog/ , sử dụng filtergiải pháp của Dmitri hoặc thực hiện $ .each trên tất cả các yếu tố và kiểm tra lặp lại .data ()


Trong trường hợp của tôi, nó ổn vì tôi đã điền trước trường ở phía máy chủ và chỉ cần tham khảo ý kiến ​​theo cách này khi tải ban đầu. Bộ lọc có thể chỉ nhanh như vậy (mỗi cái gần như chắc chắn chậm hơn) nhưng điều này chiến thắng về khả năng đọc.
Don

11

Có một :data()plugin bộ lọc chỉ làm điều này :)

Một số ví dụ dựa trên câu hỏi của bạn:

$('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

Hiệu suất sẽ không tuyệt vời so với những gì có thể , chọn từ$._cache và nắm bắt các yếu tố tương ứng là nhanh nhất, nhưng nhiều vòng và không phải là "jQuery-eye" về cách bạn tiếp cận công cụ (bạn thường đến từ phía yếu tố). Trên đỉnh đầu của tôi, tôi không chắc đây là cách nhanh nhất vì quá trình chuyển từ Id duy nhất sang thành phần tự nó bị ảnh hưởng, về mặt hiệu suất.

Bộ chọn so sánh bạn đã đề cập sẽ là tốt nhất để làm trong .filter() , không có hỗ trợ tích hợp nào cho plugin này, mặc dù bạn có thể thêm nó vào mà không gặp nhiều rắc rối.


cảm ơn câu trả lời thấu đáo Bạn có biết nếu sử dụng các data-*thuộc tính HTML5 và chọn chúng sẽ nhanh hơn chọn .data()các thuộc tính không? Ngoài ra, bất kỳ ý tưởng nào tôi có thể tìm hiểu thêm về $ ._ cache? Tôi googled cho nó, nhưng không tìm thấy nhiều.
Tauren

@Tauren - Lỗi của tôi $.cachekhông phải vậy $._cache, bạn có thể thấy cách nó được triển khai và sử dụng trong lõi jQuery tại đây: github.com/jquery/jquery/blob/master/src/data.js#L4 Khi bạn gọi .data()nó thực sự lưu trữ nó như một đối tượng trong $.cache[elementUniqueID]đó, một Id được gán khi cần theo cách bất thường cho từng thành phần, ví dụ: 1, 2, 3, v.v. ID leo đó sẽ được hiển thị trong jQuery 1.4.3. Tôi tin rằng, dựa trên các nhận xét git vào ngày khác. Tôi cho rằng tuyến HTML 5 sẽ nhanh hơn, tùy thuộc vào tối ưu hóa trình duyệt nào có sẵn (tôi chắc chắn sẽ có nhiều hơn nữa).
Nick Craver

7

Bạn có thể đặt data-*thuộc tính trên một cây du bằng cách sử dụng attr(), sau đó chọn sử dụng thuộc tính đó:

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

và bây giờ cho cây du đó, cả hai attr()data()sẽ mang lại 123 :

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

Tuy nhiên, nếu bạn sửa đổi giá trị thành 456 bằng cách sử dụng attr(), data() vẫn sẽ là 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

Vì vậy, theo tôi hiểu, có vẻ như bạn có thể tránh xa việc xen kẽ attr()data()các lệnh trong mã của bạn nếu bạn không phải làm vậy. Bởi vì attr()dường như tương ứng trực tiếp với DOM trong khidata() tương tác với 'bộ nhớ', mặc dù giá trị ban đầu của nó có thể là từ DOM. Nhưng điểm mấu chốt là cả hai hoàn toàn không nhất thiết phải đồng bộ.

Vì vậy, hãy cẩn thận.

Ở bất cứ giá nào, nếu bạn không thay đổi data-* thuộc tính trong DOM hoặc trong bộ nhớ, thì bạn sẽ không gặp vấn đề gì. Ngay khi bạn bắt đầu sửa đổi giá trị là khi các vấn đề tiềm ẩn có thể phát sinh.

Cảm ơn @Clarence Liu cho câu trả lời của @ Ash, cũng như bài đăng này .



5

Nếu bạn cũng sử dụng jQueryUI, bạn sẽ có một phiên bản (đơn giản) của :databộ chọn để kiểm tra sự hiện diện của một mục dữ liệu, do đó bạn có thể làm một cái gì đó như $("div:data(view)"), hoặc$( this ).closest(":data(view)") .

Xem http://api.jqueryui.com/data-selector/ . Tôi không biết họ đã có nó trong bao lâu, nhưng giờ nó đã ở đó!


Điều này chỉ kiểm tra sự hiện diện của mục dữ liệu như bạn đã nói. Nó không kiểm tra các giá trị (theo các tài liệu). Rất vui được biết về điều này mặc dù
Fractalf

3

Đây là một plugin giúp đơn giản hóa cuộc sống https://github.com/rootical/jQueryDataSelector

Sử dụng nó như thế:

data selector           jQuery selector
  $$('name')              $('[data-name]')
  $$('name', 10)          $('[data-name=10]')
  $$('name', false)       $('[data-name=false]')
  $$('name', null)        $('[data-name]')
  $$('name', {})          Syntax error
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.