Tổ chức javascript trong ứng dụng Rails với Turbolinks

Javascript ngày một phổ dụng và trở thành một phần không thể thiêú trong một ứng dụng. Javascript có thể được sử dụng như một đoạn script nhỏ để xử lý sự kiện click cho một button hay đến một Javascript framework với đầy đủ tiện ích và tính năng trên client side của ứng dụng. Nhìn chung, hành vi của Javascript sẽ ảnh hưởng như sau:

  • Hành vi "Always On"
  • Hành vi được kích hoạt từ thao tác của User(như click, enter,...)

Các ứng dụng Rails thường sử dụng Turbolinks để tăng hiệu năng của trang web. Vậy Turbolinks là gì và làm sao để tổ chức Javascript bằng Turbolinks? Ở bài viết này mình sẽ hướng dịch và dẫn ra chủ yếu là từ bài viết này 😄 ORGANIZING JAVASCRIPT IN RAILS APPLICATION WITH TURBOLINKS

I. Turbolinks hoạt động như thế nào?

Tư tưởng của Turbolinks cũng khá đơn giản là Turbolinks sẽ chặn tất cả thêm một sự kiện (event) click cho tất cả các thẻ <a> trên trang. Nếu browser hỗ trợ PushState, khi bạn click vào thẻ bất kì trên trang thay vì redirect tới một trang khác thì Turbolinks sẽ tạo một Ajax request, sau khi nhận được kết quả trả về sẽ thay thế toàn bộ nội dung của thẻ body bằng nội dung của thẻ body trong kết quả trả về. Do việc không phải load lại các Javascript trên thẻ head nên trang web sử dụng Turbolinks hoạt động khá nhanh.

II. Tổ chức

Trước tiên, tạo một view để sử dụng Javascript. Tôi vẫn thích đặt tên class của thẻ body là tên controller kết hợp với action_name, ở đây controller là: posts và action_name là index. Điều này có thể không đúng theo chuẩn viết code của các bạn 😄

<body class="posts index">
  <%= yield %>
</body>

Khi tạo ứng dụng Rails, file Application Manifest mặc định sẽ như sau:

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

Trước tiên, tôi sẽ xóa dòng //= require_tree. Tôi làm vậy bởi vì nếu không tất cả file Javascript sẽ được load vào ứng dụng của chúng ta theo thứ tự alphabetical. Điều này là dư thừa và không cần thiết. Như bạn thấy bên dưới có một file khởi tạo cần được load trước các file Javascript khác. Chúng ta sẽ xóa comments khởi đầu file để code nhìn Dry hơn. Và đây là file mới:

//= require jquery
//= require jquery_ujs
//= require turbolinks
  1. Khởi tạo Hãy bắt đầu bằng việc thêm file app/assets/javascripts/init.coffee như sau:
window.App ||= {}

App.init = ->
  $("a, span, i, div").tooltip()

$(document).on "turbolinks:load", ->
  App.init

Chúng ta hãy hiểu đoạn code này:

  • window.App ||= {} Chúng ta tạo đối tượng App trên cửa sổ nên tính năng được thêm vào đối tượng có sẵn trong suốt ứng dụng.
  • Tiếp theo là định nghĩa một hàm khởi tạo trên App để khởi tạo plugin Jquery phổ biến và sử dụng các thư viện khác:
App.init = ->
  $("a, span, i, div").tooltip()

Gọi $("a, span, i, div").tooltip() sẽ khởi tạo Bootstrap Tooltips. Hiển nhiên, nếu bạn không sử dụng các Bootstrap Tooltip, bạn sẽ không thể gọi tooltip ở đây, nhưng kết hợp với dòng tiếp theo, chúng ta sẽ thấy tại sao nó lại hoạt động.

  • Có thể nhiều người đã biết, khi Turbolinks được kích hoạt trong ứng dụng jQuery $(document).ready không có hiệu ứng từ trang này sang trang khác. Để gọi hàm init() khi chuyển tiếp trang, chúng ta sẽ nối vào sự kiện turbolinks:load:
$(document).on "turbolinks:load", ->
 App.init()

Lưu ý: turbolinks:load tự động trigger các xử lý khi chuyển đổi trang nên bạn không cần thêm vào đầu trang bất cứ xử lý đặc biệt nào. 2. Cuối cùng chúng ta require file init.coffee vào file js tổng:

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require init

III. Chức năng “Always On”

Bây giờ hãy xem thêm một số hành vi của Javascript. Giả sử trang của chúng ta sẽ hiển thị dữ liệu dưới dạng biểu đồ. Bất đầu bằng việc thêm một file thực hiện chức năng đó:

# app/assets/javascripts/app.chart.coffee

class App.Chart
  constructor: (@el) ->
    # intialize some stuff

  render: ->
    # do some stuff

$(document).on "turbolinks:load", ->
  chart = new App.Chart $("#chart")
  chart.render()

Tôi đã note lại một vài thứ để giải thích ở đây:

  • Structure Tôi tạo một class trong namespace tên là App - giống như cách chúng ta khởi tạo trong app/assets/javascripts/init.coffee. Nó sẽ tạo ra class với tên Chart thực hiện chức năng cụ thể. Bạn có thể nhìn thấy file có dạng:
    |
    |
    Định nghĩa lớp
    |
    |
    |
    Lời gọi hàm
    |
    

Mặc dù nhìn có vẻ là hiển nhiên nhưng rất quan trọng đẻ lưu ý ở đây. Tôi đã nhận ra rằng nó cung cấp một cấu trúc dự đoán được cho phép chúng ta mở bất kỳ tập tin coffeescript đã viết trong dự án và thường biết nơi để tìm cái gì.

  • Turbolinks-Proof Chúng tôi gọi hàm này là “Always On” bởi vì như bạn có thể nhận thấy, sử dụng trình lắng nghe sự kiện $(document).on "turbolinks:load", ->, chúng ta biết rằng Turbolinks trigger sự kiện cho mỗi trang được chuyển tiếp sau đó.
  • Thêm vào file Manifest
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require init
//= require app.chart

IV. Chức năng Javascript trên một trang cụ thể

Dĩ nhiên chúng ta không muốn biểu đồ luôn hiển thị trên mọi trang. Trong trường hợp này, chúng ta sẽ sử dụng chức năng “Always On” cho một trang cụ thể. Chúng ta có thể giới hạn các trang với một số chức năng được load bằng cách sử dụng tên các class mà đã được thêm vào body của layout ở phần đầu. Trong trường hợp này, sự kiện chỉ được gọi cho những trang cụ thể có chứ class định nghĩa.

$(document).on "turbolinks:load", ->
  return unless $(".posts.index").length > 0
  f = new App.Chart $("#chart")
  f.render()

Đoạn code này có lẽ đã quá rõ ràng nên tôi sẽ không giải thích thêm nữa.

V. Tổng kết

  • Sử dụng các kỹ thuật trên, chúng ta có thể giữ Javascript trong các ứng dụng Rails dễ dàng để tổ chức và tiên đoán hơn. Chúng ta có thể dễ dàng biết rằng các tập tin nhìn chung sẽ giống nhau.

  • Một điều mà làm cho tôi cảm thấy tốt về cách tiếp cận này là không có ma thuật thực sự hoặc các plugin bổ sung. Nó sử dụng tất cả các công cụ chúng ta đã có trong một ứng dụng Rails cơ bản, điều này dễ dàng duy trì và cập nhật sau này.

Nguồn bài dịch: http://brandonhilkert.com/blog/organizing-javascript-in-rails-application-with-turbolinks/


All Rights Reserved