Lỗi sử dụng câu lệnh document ready function trong javascript năm 2024

basically.. your waiting for the DOM to be ready and then run the code when the window has loaded (images, links, etc.. )

the reason I put the window.load inside the DOM ready() is because sometimes the window.load event can fire before the DOM is ready..

jQuery là một trong những framework được yêu thích và sử dụng bởi phần lớn lập trình viên front-end. jQuery cung cấp hàm và phương thức giúp đơn giản hóa tác vụ thường gặp trong quá trình viết web. Giờ đây, khi các trình duyệt ngày càng được phát triển và hỗ trợ nhiều tính năng hơn, chúng ta có thể thay thế những tác vụ của jQuery bằng các phương thức mặc định.

Điều này đem đến nhiều lợi ích như:

  • Không phụ thuộc vào jQuery, đồng thời người dùng không cần phải download thêm thư viện
  • Được trình duyệt tối ưu, có khả năng tăng hiệu suất (dù chỉ là chút xíu)
  • Về mặt lâu dài, sử dụng phương thức mặc định của trình duyệt đảm bảo tính tương thích trong ứng dụng, đặc biệt hữu ích phải bảo trì những ứng dụng cũ.

Chính vì thế, Ehkoo sẽ giới thiệu cho các bạn một số cách thay thế jQuery bằng JavaScript thuần, hay còn gọi là “vanilla JS”.

Kiểm tra khi trang được tải xong

Một trang web không thể thao tác an toàn trừ khi document đã sẵn sàng (ready): các tập tin JS, CSS hay hình ảnh được tải hết, cấu trúc DOM được xây dựng xong. Chính vì vậy, các lập trình viên được khuyến khích đặt toàn bộ code bên trong hàm

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

0:

$(document).ready(function () {
  console.log('Ready')
})

// hoặc
$(function () {
  console.log('Ready')
})

Với vanilla JS, bạn có thể dùng

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

1.

window.onload = function () {
  console.log('Ready!')
}

Điểm khác biệt giữa

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

1 và sự kiện

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

3 là

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

3 không chờ đợi các tài nguyên khác như JS, CSS hay hình ảnh được tải, mà sự kiện này được kích hoạt ngay khi cấu trúc DOM được xây dựng xong.

Xem thêm về

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

5 ở MDN.

Hoặc bạn cũng có thể dùng thư viện

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

6.

Chọn elements

jQuery giúp chúng ta chọn các element trong cây DOM rất dễ dàng

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

Với vanilla JS, bạn có thể dùng những phương thức sau, hỗ trợ bởi tất cả trình duyệt kể cả IE8+:

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

Bạn cần lưu ý sự khác nhau giữa

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

7 và

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

8.

// Chọn bằng ID
$('
# myElement')

// Chọn bằng CSS class
$('.myElement')

// Chọn bằng tên thẻ
$('div')

// Phức tạp hơn
$('article
# first p.summary')

9 sẽ trả về một danh sách

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

0 các element phù hợp với điều kiện tìm kiếm, trong khi

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

1 chỉ trả về một element duy nhất. Do đó,

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

2 sẽ trả về thẻ DIV đầu tiên được tìm thấy, chứ không phải tất cả thẻ DIV trong trang.

Lắng nghe sự kiện

Xử lý sự kiện là một phần rất quan trọng trong JavaScript, và với jQuery bạn có thể lắng nghe sự kiện bằng phương thức

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

3.

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

Với vanilla JS, chúng ta phải dùng phương thức

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

4 dài dòng hơn.

someElement.addEventListener('click', function (e) {
  // TODO event handler logic
})

Nếu bạn muốn sự kiện chỉ được xử lý một lần, giống như phương thức

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

5 của jQuery.

someElement.addEventListener(
  'click',
  function (e) {
    // TODO event handler logic
  },
  { once: true },
)

Promise

Bản thân jQuery có đính kèm một lớp Deferred, giúp bạn thực hiện các thao tác bất đồng bộ mà không phải lâm vào callback-hell.

function getDataFromApi() {
  const defer = $.Deferred()
  MyApiService.call({
    onSuccess(result) {
      defer.resolve(result)
    },
    onError(err) {
      defer.reject(err)
    },
  })

  return defer.promise()
}

Mặc dù trông có vẻ giống Promise, nhưng Deferred có nhiều phương thức hỗ trợ hơn, chẳng hạn như

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

6,

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

7,

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

8…

Với vanilla JS, hầu hết các trình duyệt đều đã hỗ trợ Promise theo mặc định.

function getDataFromApi() {
  return new Promise((resolve, reject) => {
    MyApiService.call({
      onSuccess: resolve,
      onError: reject,
    })
  })
}

Gửi AJAX requests

Hầu hết các bạn cũng đều biết, AJAX giúp chúng ta tương tác với server một cách bất đồng bộ. jQuery hỗ trợ gửi AJAX requests bằng

// Chọn bằng ID
document.getElementById('myElement')
document.querySelector('
# myElement')

// Chọn bằng CSS class
document.getElementsByClassName('myElement')
document.querySelectorAll('.myElement')

// By tag name
document.getElementsByTagName('div')
document.querySelectorAll('div')

// Phức tạp hơn
document.querySelectorAll('article
# first p.summary')

9 cùng với với các phương thức hỗ trợ như

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

0 hay

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

1.

$.get('ajax/test.html', function (data) {
  $('.result').html(data)
  alert('Load was performed.')
})

Với vanilla JS, bạn có thể dùng API mới:

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

2

window.onload = function () {
  console.log('Ready!')
}

0

Xem thêm về Fetch API.

Thao tác trên thuộc tính

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

3 của một element

jQuery có các phương thức

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

4,

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

5,

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

6 và

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

7 để thao tác trên thuộc tính

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

3 của một element.

window.onload = function () {
  console.log('Ready!')
}

1

Không cần jQuery, chúng ta vẫn có thể làm điều này dễ dàng với thuộc tính

$(someElement).on('click', function (e) {
  // TODO event handler logic
})

9 của element.

window.onload = function () {
  console.log('Ready!')
}

2

Xem thêm về classList.

Animation

jQuery hỗ trợ các hiệu ứng

someElement.addEventListener('click', function (e) {
  // TODO event handler logic
})

0… theo mặc định.

window.onload = function () {
  console.log('Ready!')
}

3

Với sự hỗ trợ của CSS animation, chúng ta có thể đạt được hiệu quả tương tự.

window.onload = function () {
  console.log('Ready!')
}

4

window.onload = function () {
  console.log('Ready!')
}

5

Bạn cũng có thể dùng sẵn thư viện animate.css, cung cấp sẵn các hiệu ứng thông dụng như fading, sliding, bouncing…

Đối với các hiệu ứng animation phức tạp khác, bạn có thể dùng velocity.js, anime.js, Popmotion hay GreenSock. Các thư viện này hứa hẹn đem đến hiệu suất tốt hơn cho

someElement.addEventListener('click', function (e) {
  // TODO event handler logic
})

1.

Ẩn/hiện elements

Ẩn/hiện elements là một trong những tác vụ phổ biến, và jQuery làm điều này trong vòng một nốt nhạc:

window.onload = function () {
  console.log('Ready!')
}

6

Với Javascript, điều này cũng chẳng khó khăn hơn là bao:

window.onload = function () {
  console.log('Ready!')
}

7

Thao tác với DOM

Thao tác với DOM rất dễ dàng khi sử dụng jQuery. Ví dụ khi bạn muốn chèn thêm một phần tử

someElement.addEventListener('click', function (e) {
  // TODO event handler logic
})

2 vào

someElement.addEventListener('click', function (e) {
  // TODO event handler logic
})

3:

window.onload = function () {
  console.log('Ready!')
}

8

Vanilla JS cũng có thể làm điều này một cách dễ dàng:

window.onload = function () {
  console.log('Ready!')
}

9

Tuy nhiên bạn cũng có thể nhận thấy cách làm trên hoàn toàn không ổn về lâu dài, vì bất tiện và khó bảo trì. Cách tốt hơn là sử dụng một thư viện virtual DOM nhỏ gọn, chẳng hạn như redom, ultradom hay preact.

Kết luận

Bạn có nên từ bỏ jQuery không? Câu trả lời là… hên xui. Nếu dự án của bạn đang dùng một thư viện ngoài phụ thuộc vào jQuery, chẳng hạn như FancyBox, và việc thay đổi có thể đòi hỏi nhiều thời gian để hoàn thành, thì câu trả lời là không nên. Nhưng nếu bạn chọn một thư viện mới thì nên ưu tiên những giải pháp không cần jQuery.