jquery_ujs 對 rails 來說,是一個非常重要的組件,它包含在 rails 的默認組件之中。
jquery ujs 包含一些非常便捷的功能,比如確認對話框、觸發 ajax、自動禁用表單提交按鈕等,本文主要討論的是觸發 ajax 的功能。
通過添加簡單的標簽屬性,jquery ujs 可以把一個普通的鏈接或者表單轉換成 ajax 提交,而不需要寫 JavaScript 代碼。
%= link_to '關閉項目', close_project_path(project), remote: true, method: :post %>
上面的代碼會生成如下的代碼
a href="/projects/1/close" data-remote="true" data-method="post">關閉項目/a>
當用戶點擊后,它會觸發一個指向地址 /projects/1/close,method 為 post 的 ajax 請求,而不是 get 的 普通請求,這樣使得實現 ajax 調用變得非常便捷。
網速慢導致的問題
事情并不都是美好的,在網速比較慢的時候,jquery ujs 的這個實現會出問題,如果文檔還沒有加載完成,用戶就點擊了鏈接,頁面會發起一個到鏈接地址的 GET 請求,頁面會跳轉,但指向該地址的 GET 請求可以并不存在,這樣就會出錯。
有用戶有提過一個相關的 Issue,但是開發者并沒有受理,然而網速慢是中國的國情,問題我們還是得處理,借助于 CSS3 的一些特性,這個問題其實也不難解決。
pointer-events
pointer-events: none;
The element is never the target of mouse events; however, mouse events may target its descendant elements if those descendants have pointer-events set to some other value. In these circumstances, mouse events will trigger event listeners on this parent element as appropriate on their way to/from the descendant during the event capture/bubble phases.
這個屬性可以禁止元素的點擊事件,因為一般 CSS 是先加載的,我們只要控制在頁面加載完成之前給 jquery ujs 相關的元素應用 pointer-events: none; 樣式,在頁面加載完成后再去除該樣式,就可以解決網速慢的情況下,頁面沒有加載完成時用戶點擊 rmote 鏈接導致的錯誤了。
解決方案
添加如下的全局樣式,默認情況下含有 data-remote 和 data-method 屬性的標簽不可點擊,除非 body 元素含有名為 ready 的 css class。
[data-remote], [data-method] {
pointer-events: none;
button, input[type=submit] {
pointer-events: none;
}
}
body.ready {
[data-remote], [data-method] {
pointer-events: auto;
button, input[type=submit] {
pointer-events: auto;
}
}
}
然后通過段簡單的腳本讓頁面加載后給 body 元素添加 ready class
$(document).ready ->
$('body').addClass('ready')
于是,問題輕松的就解決了。