jQuery vs document.querySelector ALL


161

Tôi đã nghe nhiều lần rằng tài sản mạnh nhất của jQuery là cách nó truy vấn và thao tác các phần tử trong DOM: bạn có thể sử dụng các truy vấn CSS để tạo các truy vấn phức tạp rất khó thực hiện trong javascript thông thường. Tuy nhiên, theo tôi biết, bạn có thể đạt được kết quả tương tự với document.querySelectorhoặc document.querySelectorAll, được hỗ trợ trong Internet Explorer 8 trở lên.

Vì vậy, câu hỏi đặt ra là: tại sao 'rủi ro' chi phí của jQuery nếu tài sản mạnh nhất của nó có thể đạt được bằng JavaScript thuần túy?

Tôi biết jQuery không chỉ có các bộ chọn CSS, ví dụ AJAX trình duyệt chéo, đính kèm sự kiện hay, v.v. Nhưng phần truy vấn của nó là một phần rất lớn trong sức mạnh của jQuery!

Có suy nghĩ gì không?


4
(1) DOM traversal / sửa đổi nhanh hơn và dễ dàng hơn với jQuery. (2) Nó thêm các bộ chọn riêng mà không hoạt động trong các querySelectorphương thức. (3) Thực hiện các cuộc gọi AJAX nhanh hơn và dễ dàng hơn với jQuery. (4) Hỗ trợ trong IE6 +. Tôi chắc chắn còn nhiều điểm nữa có thể được thực hiện.
James Allardice

12
(5) ... tốc ký $ () cho những người đánh máy lười biếng là điều bắt buộc.
Dexter Huinda

4
có dễ hơn, tại sao nhanh hơn? jQuery dịch sang javascript thông thường theo như tôi biết ...
Joel_Blum

4
@ James ALLardice, "tất cả những thứ lộn xộn" đối với XMLHttpRequest trên trình duyệt chéo có thể là 30 dòng mã mà bạn viết một lần và đưa vào thư viện của riêng bạn.
RobG

6
@RobG - Vâng, tôi không nói chỉ sử dụng jQuery nếu đó là tất cả những gì bạn đang cố gắng sử dụng nó cho. Đó chỉ là một trong những lợi ích. Nếu bạn cần dễ dàng truy cập DOM, AJAX và querySelectorAll, và bạn cần tất cả để hoạt động trong các trình duyệt cũ hơn, thì jQuery là một lựa chọn rõ ràng. Tôi không nói rằng bạn nên sử dụng nó như thế này .
James Allardice

Câu trả lời:


127

document.querySelectorAll() có một số điểm không nhất quán trên các trình duyệt và không được hỗ trợ trong các trình duyệt cũ hơn Điều này có thể sẽ không gây ra bất kỳ rắc rối nào nữa hiện nay . Nó có một cơ chế phạm vi rất không trực quan và một số tính năng không đẹp khác . Ngoài ra với javascript, bạn gặp khó khăn hơn khi làm việc với các tập kết quả của các truy vấn này, trong nhiều trường hợp bạn có thể muốn thực hiện. jQuery cung cấp chức năng để làm việc trên chúng như: filter(), find(), children(),parent() , map(), not()và nhiều hơn nữa. Chưa kể đến khả năng jQuery hoạt động với các bộ chọn lớp giả.

Tuy nhiên, tôi sẽ không coi những thứ này là các tính năng mạnh nhất của jQuery mà là những thứ khác như "hoạt động" trên dom (sự kiện, kiểu dáng, hoạt hình & thao tác) theo cách tương thích chéo hoặc giao diện ajax.

Nếu bạn chỉ muốn công cụ chọn từ jQuery, bạn có thể sử dụng chính một jQuery đang sử dụng: Sizzle Bằng cách đó bạn có sức mạnh của công cụ Selector jQuery mà không cần chi phí khó chịu.

EDIT: Chỉ để ghi lại, tôi là một người hâm mộ JavaScript vanilla lớn. Tuy nhiên, đôi khi bạn cần 10 dòng JavaScript để viết 1 dòng jQuery.

Tất nhiên bạn phải có kỷ luật để không viết jQuery như thế này:

$('ul.first').find('.foo').css('background-color', 'red').end().find('.bar').css('background-color', 'green').end();

Điều này cực kỳ khó đọc, trong khi phần sau khá rõ ràng:

$('ul.first')
   .find('.foo')
      .css('background-color', 'red')
.end()
   .find('.bar')
      .css('background-color', 'green')
.end();

JavaScript tương đương sẽ phức tạp hơn nhiều được minh họa bằng mã giả ở trên:

1) Tìm phần tử, xem xét lấy tất cả phần tử hoặc chỉ phần tử đầu tiên.

// $('ul.first')
// taking querySelectorAll has to be considered
var e = document.querySelector("ul.first");

2) Lặp lại mảng các nút con thông qua một số vòng lặp (có thể lồng nhau hoặc đệ quy) và kiểm tra lớp (danh sách lớp không có sẵn trong tất cả các trình duyệt!)

//.find('.foo')
for (var i = 0;i<e.length;i++){
     // older browser don't have element.classList -> even more complex
     e[i].children.classList.contains('foo');
     // do some more magic stuff here
}

3) áp dụng kiểu css

// .css('background-color', 'green')
// note different notation
element.style.backgroundColor = "green" // or
element.style["background-color"] = "green"

Mã này sẽ ít nhất gấp hai lần số dòng mã bạn viết bằng jQuery. Ngoài ra, bạn sẽ phải xem xét các vấn đề trên nhiều trình duyệt sẽ làm giảm lợi thế tốc độ nghiêm trọng (bên cạnh độ tin cậy) của mã gốc.


33
Những loại không nhất quán nào querySelectorAllcó giữa các trình duyệt? Và làm thế nào để sử dụng jQuery giải quyết điều này, vì jQuery sử dụng querySelectorAll khi có sẵn?

3
Đúng, một dòng mã có thể chứa các chuỗi mã vô tận có thể gây khó chịu trong quá trình gỡ lỗi.
Dexter Huinda

1
"2) lặp lại qua mảng mã con thông qua một số vòng lặp (có thể lồng nhau hoặc đệ quy) và kiểm tra lớp" << Đây là một tổng số tào lao. Bạn có thể sử dụng querySelectorAll trên phần tử ở bước trước.
Vanuan

5
@Vanuan điều này có thể không cần thiết, nhưng nếu bạn đã đọc kỹ câu trả lời của tôi, bạn sẽ nhận thấy, truy vấn đó có một vấn đề phạm vi nghiêm trọng có thể cung cấp cho bạn rất nhiều thông tin sai khi sử dụng theo cách bạn đề xuất. Tuy nhiên, trong khi bạn có thể tự do lên hoặc xuống vì một số lý do khó chịu, tôi nghĩ đó không phải là lý do để sử dụng ngôn ngữ thô lỗ.
Christoph

2
@Christoph Vì việc này rất dễ, tôi đã thêm tính tương thích cho IE8 trở lên. Vẫn là lợi thế tốc độ rất lớn (5-20 lần). Việc mã sẽ chạy chậm hơn trong trình duyệt cũ như IE8 chỉ là một giả định sai.
Pascalius

60

Nếu bạn đang tối ưu hóa trang của mình cho IE8 hoặc mới hơn, bạn thực sự nên xem xét liệu bạn có cần jquery hay không. Các trình duyệt hiện đại có nhiều tài sản mà jquery cung cấp.

Nếu bạn quan tâm đến hiệu suất, bạn có thể có lợi ích hiệu suất đáng kinh ngạc (nhanh hơn 2-10) bằng cách sử dụng javascript gốc: http://jsperf.com/jquery-vs-native-selector-and-element-style/2

Tôi đã chuyển đổi một div-tagcloud từ jquery sang javascript gốc (tương thích IE8 +), kết quả rất ấn tượng. Nhanh hơn 4 lần chỉ với một chút chi phí.

                    Number of lines       Execution Time                       
Jquery version :        340                    155ms
Native version :        370                    27ms

You Might Not Need Jquery cung cấp một cái nhìn tổng quan thực sự hay, phương thức gốc nào thay thế cho phiên bản trình duyệt nào.

http://youmightnotneedjquery.com/


Phụ lục: So sánh tốc độ hơn nữa cách các phương thức bản địa cạnh tranh với jquery


Tổng quan đẹp mặc dù một số ví dụ mã sai ... Ví dụ: $(el).find(selector)không bằng el.querySelectorAll(selector)và hiệu suất của các phương thức gốc thường khá kinh khủng: stackoverflow.com/q/14647470/1047823
Christoph

@Christoph Bạn có thể giải thích, tại sao bạn nghĩ các phương pháp là khác nhau? Tất nhiên, có những trường hợp cạnh mà jquery có thể hoạt động tốt hơn, nhưng tôi chưa thấy một trường hợp nào cho DOM-Manipulation.
Pascalius

1
Không cần phải giải thích thêm, chỉ cần đọc câu trả lời của tôi, nhìn vào fiddle và bài viết tôi liên kết đến. Ngoài ra, (ít nhất là atm) hầu hết các phương thức Array gốc đều kém hơn về tốc độ so với cách triển khai js ngây thơ (như tôi đã liên kết trong câu hỏi trong nhận xét đầu tiên của mình). Và đây không phải là trường hợp cạnh, mà là trường hợp tiêu chuẩn. Nhưng một lần nữa, trọng tâm chính của câu hỏi này không phải là tốc độ.
Christoph

2
@Christoph Tất nhiên, các phương thức này không bằng nhau 100% và jquery thường cung cấp nhiều tiện lợi hơn. Tôi đã cập nhật câu trả lời để cho thấy rằng đây chỉ là một trường hợp cạnh, tôi thực sự không thể tìm thấy bất kỳ trường hợp nào khác mà jquery hoạt động tốt hơn. Không có trọng tâm chính của câu hỏi.
Pascalius

+1 câu trả lời tuyệt vời! Tôi đã dần thay thế mã jQuery cũ bằng JavaScript thô trong 4 hoặc 5 năm qua ở bất cứ đâu và bất cứ khi nào có thể .. Tất nhiên, jQuery rất tốt cho một số thứ và tôi sử dụng nó cho những thứ đó khi tôi cảm thấy mình có được lợi ích vững chắc.
Có Barry

13

Để hiểu tại sao jQuery rất phổ biến, điều quan trọng là phải hiểu chúng ta đến từ đâu!

Khoảng một thập kỷ trước, các trình duyệt hàng đầu là IE6, Netscape 8 và Firefox 1.5. Quay trở lại những ngày đó, có rất ít cách để trình duyệt chéo để chọn một phần tử từ DOM bên cạnh đó Document.getElementById().

Vì vậy, khi jQuery được phát hành trở lại vào năm 2006 , nó đã mang tính cách mạng. Trước đó, jQuery đặt tiêu chuẩn cho cách dễ dàng chọn / thay đổi các phần tử HTML và kích hoạt các sự kiện, bởi vì tính linh hoạt và hỗ trợ trình duyệt của nó là chưa từng có.

Bây giờ, hơn một thập kỷ sau, rất nhiều tính năng khiến jQuery trở nên phổ biến đã được đưa vào tiêu chuẩn javaScript:

Chúng thường không có sẵn vào năm 2005. Thực tế là ngày nay chúng rõ ràng đặt ra câu hỏi tại sao chúng ta nên sử dụng jQuery. Và thực sự, mọi người đang ngày càng tự hỏi liệu chúng ta có nên sử dụng jQuery hay không .

Vì vậy, nếu bạn nghĩ rằng bạn hiểu JavaScript đủ tốt để làm mà không cần jQuery, vui lòng làm! Đừng cảm thấy bị buộc phải sử dụng jQuery, chỉ vì rất nhiều người khác đang làm điều đó!


7

Đó là bởi vì jQuery có thể làm được nhiều hơn thế querySelectorAll.

Trước hết, jQuery (và đặc biệt là Sizzle), hoạt động cho các trình duyệt cũ hơn như IE7-8 không hỗ trợ các bộ chọn CSS2.1-3.

Thêm vào đó, Sizzle (là công cụ chọn sau jQuery) cung cấp cho bạn rất nhiều công cụ chọn nâng cao hơn, như lớp :selectedgiả, :not()bộ chọn nâng cao , cú pháp phức tạp hơn như $("> .children")v.v.

Và nó thực hiện nhiều trình duyệt, hoàn hảo, cung cấp tất cả những gì jQuery có thể cung cấp (plugin và API).

Có, nếu bạn nghĩ rằng bạn có thể dựa vào các bộ chọn id và lớp đơn giản, jQuery là quá nhiều đối với bạn và bạn sẽ phải trả một khoản tiền quá mức. Nhưng nếu bạn không và muốn tận dụng mọi ưu điểm của jQuery, thì hãy sử dụng nó.


7

Công cụ chọn Sizzle của jQuery có thể sử dụng querySelectorAllnếu có sẵn. Nó cũng làm dịu đi sự không nhất quán giữa các trình duyệt để đạt được kết quả thống nhất. Nếu bạn không muốn sử dụng tất cả jQuery, bạn chỉ có thể sử dụng Sizzle một cách riêng biệt. Đây là một bánh xe khá cơ bản để phát minh.

Dưới đây là một số lựa chọn anh đào từ nguồn hiển thị loại điều jQuery (w / Sizzle) sắp xếp cho bạn:

Chế độ quirks Safari:

if ( document.querySelectorAll ) {
  (function(){
    var oldSizzle = Sizzle,
      div = document.createElement("div"),
      id = "__sizzle__";

    div.innerHTML = "<p class='TEST'></p>";

    // Safari can't handle uppercase or unicode characters when
    // in quirks mode.
    if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
      return;
    }

Nếu bảo vệ đó thất bại, nó sử dụng phiên bản Sizzle không được cải tiến querySelectorAll. Hơn nữa, có các xử lý cụ thể cho sự không nhất quán trong IE, Opera và trình duyệt Blackberry.

  // Check parentNode to catch when Blackberry 4.6 returns
  // nodes that are no longer in the document #6963
  if ( elem && elem.parentNode ) {
    // Handle the case where IE and Opera return items
    // by name instead of ID
    if ( elem.id === match[3] ) {
      return makeArray( [ elem ], extra );
    }

  } else {
    return makeArray( [], extra );
  }

Và nếu thất bại, nó sẽ trả về kết quả oldSizzle(query, context, extra, seed).


6

Về khả năng duy trì mã, có một số lý do để gắn bó với một thư viện được sử dụng rộng rãi.

Một trong những vấn đề chính là chúng được ghi chép tốt và có các cộng đồng như ... nói ... stackexchange, nơi có thể tìm thấy trợ giúp với các thư viện. Với một thư viện được mã hóa tùy chỉnh, bạn có mã nguồn và có thể là tài liệu hướng dẫn, trừ khi (các) người viết mã dành nhiều thời gian để ghi lại mã hơn là viết mã, điều này rất hiếm.

Viết thư viện của riêng bạn có thể phù hợp với bạn , nhưng người thực tập ngồi ở bàn kế bên có thể có thời gian dễ dàng hơn để tăng tốc với một cái gì đó như jQuery.

Gọi nó là hiệu ứng mạng nếu bạn thích. Điều này không có nghĩa là mã sẽ vượt trội trong jQuery; chỉ là bản chất ngắn gọn của mã giúp dễ dàng nắm bắt cấu trúc tổng thể cho các lập trình viên ở mọi cấp độ kỹ năng, nếu chỉ vì có nhiều mã chức năng hiển thị cùng một lúc trong tệp bạn đang xem. Theo nghĩa này, 5 dòng mã tốt hơn 10.

Tóm lại, tôi thấy những lợi ích chính của jQuery là mã ngắn gọn và có mặt khắp nơi.


6

Đây là một so sánh nếu tôi muốn áp dụng cùng một thuộc tính, ví dụ: ẩn tất cả các thành phần của lớp "my-class". Đây là một lý do để sử dụng jQuery.

jQuery:

$('.my-class').hide();

JavaScript:

var cls = document.querySelectorAll('.my-class');
for (var i = 0; i < cls.length; i++) {
    cls[i].style.display = 'none';
}

Với jQuery đã quá phổ biến, lẽ ra họ đã làm cho document.querySelector () hoạt động giống như $ (). Thay vào đó, document.querySelector () chỉ chọn phần tử phù hợp đầu tiên làm cho nó chỉ hữu ích một nửa.


4
Tôi sẽ làm một .forEach ở đây.
Phillip Senn

Vâng, bạn luôn có thể đi với một lộ trình dễ dàng hơn document.querySelectorAll('.my-class').forEach(el => el.style.display = 'none');. Tuy nhiên, ngay cả khi ngắn hơn, hiệu suất bản địa khôn ngoan luôn tốt hơn.
Alain Cruz

Từ quan điểm của người dùng, mọi thứ xảy ra trong vòng chưa đến 0,1 giây, sẽ xảy ra ngay lập tức. Do đó, bản địa thậm chí còn nhanh hơn, chỉ tốt hơn trong trường hợp khi jQuery triển khai chậm hơn 0,1 giây. Và trong ứng dụng thế giới thực, nó không bao giờ là trường hợp.
yurin

3

như trang web chính thức nói: "jQuery: The Write Less, Do More, JavaScript Library"

hãy thử dịch mã jQuery mà không cần bất kỳ thư viện nào

$("p.neat").addClass("ohmy").show("slow");

1
Tôi đồng ý với điều đó, tuy nhiên những gì về khả năng đọc? Làm thế nào bạn có thể ghi lại các dòng mã dài với rất nhiều điều không liên quan xảy ra? Làm thế nào bạn có thể gỡ lỗi những quái vật như vậy?
Joel_Blum

@ user1032663 đó là vấn đề về quy ước tài liệu.
Christoph

1
Giải pháp thay thế cho jQuery (hoặc bất kỳ thư viện "phổ biến" nào bạn chọn) không phải là viết mọi thứ từ đầu, mà là sử dụng một thư viện phù hợp với mục đích của bạn và được viết tốt. Bạn có thể đã tự viết các phần hoặc chọn một thư viện mô-đun như MyL Library để chỉ bao gồm những gì bạn cần.
RobG

2
Ví dụ bạn đã chọn không thực sự chứng minh quan điểm của bạn: Câu hỏi đang tìm kiếm sự khác biệt trong tỉnh "bộ chọn". addClass()show()không thực sự được tính. Và như đối với $('p.neat'), bạn có thể có một cái nhìn tại querySelector / All.
kumarharsh

document.querySelectorAll('p.neat').forEach(p=>p.classList.add('ohmy'));và để CSS làm phần còn lại. Hơi còn mã, nhưng nhiều hiệu quả hơn. Tất nhiên, giải pháp của ông không có sẵn trong những ngày kế thừa IE. Phần làm nhiều hơn nữa là mỉa mai. jQuery mất khoảng một trăm dòng mã để tìm thứ gì đó, vì vậy làm nhiều hơn không phải lúc nào cũng hiệu quả.
Manngo

2

Tôi nghĩ rằng câu trả lời thực sự là jQuery đã được phát triển từ lâu trước khi querySelector/querySelectorAllcó sẵn trong tất cả các trình duyệt chính.

Bản phát hành ban đầu của jQuery là vào năm 2006 . Trên thực tế, ngay cả jQuery cũng không phải là công cụ đầu tiên triển khai các bộ chọn CSS .

IE là trình duyệt cuối cùng để thực hiện querySelector/querySelectorAll. Phiên bản thứ 8 của nó được phát hành vào năm 2009 .

Vì vậy, bây giờ, các bộ chọn thành phần DOM không còn là điểm mạnh nhất của jQuery nữa. Tuy nhiên, nó vẫn có rất nhiều ưu điểm, như các phím tắt để thay đổi nội dung css và html của phần tử, hình động, ràng buộc sự kiện, ajax.


1

Câu hỏi cũ, nhưng nửa thập kỷ sau, nó đáng để xem lại. Ở đây tôi chỉ thảo luận về khía cạnh bộ chọn của jQuery.

document.querySelector[All]được hỗ trợ bởi tất cả các trình duyệt hiện tại, cho đến IE8, do đó khả năng tương thích không còn là vấn đề nữa. Tôi cũng đã tìm thấy không có vấn đề về hiệu suất để nói (nó được cho là chậm hơn document.getElementById, nhưng thử nghiệm của riêng tôi cho thấy rằng nó nhanh hơn một chút).

Do đó, khi nói đến việc thao tác trực tiếp một phần tử, nó sẽ được ưu tiên hơn jQuery.

Ví dụ:

var element=document.querySelector('h1');
element.innerHTML='Hello';

bao la vượt trội so với:

var $element=$('h1');
$element.html('hello');

Để làm bất cứ điều gì, jQuery phải chạy qua hàng trăm dòng mã (tôi đã từng truy tìm mã như ở trên để xem jQuery thực sự đang làm gì với nó). Đây rõ ràng là một sự lãng phí thời gian của mọi người.

Chi phí đáng kể khác của jQuery là thực tế là nó bao bọc mọi thứ bên trong một đối tượng jQuery mới. Chi phí này đặc biệt lãng phí nếu bạn cần mở lại đối tượng hoặc sử dụng một trong các phương thức đối tượng để xử lý các thuộc tính đã được phơi bày trên phần tử gốc.

Tuy nhiên, nơi jQuery có một lợi thế là cách nó xử lý các bộ sưu tập. Nếu yêu cầu là đặt các thuộc tính của nhiều phần tử, jQuery có một eachphương thức dựng sẵn cho phép một cái gì đó như thế này:

var $elements=$('h2');  //  multiple elements
$elements.html('hello');

Để làm như vậy với Vanilla JavaScript sẽ cần một cái gì đó như thế này:

var elements=document.querySelectorAll('h2');
elements.forEach(function(e) {
    e.innerHTML='Hello';
});

mà một số tìm thấy nản chí.

Các bộ chọn jQuery cũng hơi khác nhau, nhưng các trình duyệt hiện đại (không bao gồm IE8) sẽ không nhận được nhiều lợi ích.

Theo quy định, tôi thận trọng không sử dụng jQuery cho các dự án mới :

  • jQuery là một thư viện bên ngoài thêm vào chi phí hoạt động của dự án và phụ thuộc vào các bên thứ ba.
  • Hàm jQuery rất tốn kém, xử lý khôn ngoan.
  • jQuery áp đặt một phương pháp cần phải học và có thể cạnh tranh với các khía cạnh khác trong mã của bạn.
  • jQuery chậm để lộ các tính năng mới trong JavaScript.

Nếu không có vấn đề nào ở trên, thì hãy làm những gì bạn muốn. Tuy nhiên, jQuery không còn quan trọng đối với việc phát triển đa nền tảng như trước đây, vì JavaScript và CSS hiện đại tiến xa hơn nhiều so với trước đây.

Điều này làm cho không đề cập đến các tính năng khác của jQuery. Tuy nhiên, tôi nghĩ rằng họ cũng cần một cái nhìn gần hơn.


1
Cú pháp của bạn thậm chí không đúng khi không đề cập đến các nội dung sai khác như "chậm hiển thị các tính năng mới trong Javascript" Công việc của JQuery thậm chí không để lộ các tính năng mới, giúp bạn dễ dàng thao tác DOM và thực hiện các công việc đơn giản có thể như 10 dòng trong Javascript. Toàn bộ bình luận của bạn không có ý nghĩa gì và có nhiều nội dung sai trong đó. Hãy xem xét cải thiện nó.
Boy pro

@Boypro Cảm ơn bình luận của bạn, nhưng nó cũng đầy lỗi. Có lẽ bạn muốn chia sẻ những gì về câu trả lời của tôi đã xúc phạm bạn rất nhiều. Cái gì không đúng thậm chí là đúng. Tốt hơn hết, bạn có thể muốn đóng góp anwser của riêng bạn. Câu hỏi là về chi phí sử dụng jQuery khi vanilla JavaScript có thể làm được rất nhiều. Hãy xem xét việc trả lời nó.
Manngo

0
$ ("# id") so với document.querySelector ALL ("# id")

Thỏa thuận là với hàm $ (), nó tạo ra một mảng và sau đó chia nhỏ cho bạn nhưng với document.querySelectorAll () nó tạo ra một mảng và bạn phải phá vỡ nó.


0

Chỉ cần một nhận xét về điều này, khi sử dụng lite thiết kế vật liệu, bộ chọn jquery không trả lại tài sản cho thiết kế vật liệu vì một số lý do.

Dành cho:

<div class="logonfield mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
        <input class="mdl-textfield__input" type="text" id="myinputfield" required>
        <label class="mdl-textfield__label" for="myinputfield">Enter something..</label>
      </div>

Những công việc này:

document.querySelector('#myinputfield').parentNode.MaterialTextfield.change();

Điều này không:

$('#myinputfield').parentNode.MaterialTextfield.change();
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.