Rails Unobtrusive JavaScript (UJS) 深度研究
WriterShelf™ is a unique multiple pen name blogging and forum platform. Protect relationships and your privacy. Take your writing in new directions. ** Join WriterShelf**
WriterShelf™ is an open writing platform. The views, information and opinions in this article are those of the author.
Article info
This article is part of:
Categories:
Tags:
Date:
Published: 2018/12/21 - Updated: 2020/03/13
Total: 2710 words
Like
or Dislike
About the Author
很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
就,這會一點點,那會一點點⋯⋯
Comments
謝謝你的這篇文章,想請問一下,其它框架有哪些類似 UJS 的套件嗎?或是純前端但是也具備類似 UJS 的框架?Vue.js 也能作到資料綁定,但是我不太確定它是否有本文提到的這些功能?
其他的 web framework 我真的不熟,很抱歉不能回答你的問題。
我個人認為 UJS 的發明,主要就是因為 Rails 本身是一個網站的後台開發平台,為了要讓 Rails 所開發的網頁,盡量不要寫 JavaScript 而誕生的,畢竟很多後台工程師對前端不熟,我就算一個啦,不熟前端又碰到 UJS,說實話,我剛開始真是很朦朧的。
我對前端的了解還停留在 JQuery 跟 JavaScript,前端的世界變得好快,學得好累啊。
More to explore
UJS 是啥?
寫 Rails 的人,一定會常聽到 UJS,但是 UJS 到底是啥?我想很多人也不會去深度研究,反正,好像也感覺不到,直到有一天,被咬到了,才會「哇」,笑。
UJS 是 Unobtrusive JavaScript 英文縮寫,Unobtrusive 的英文就是“低調”的意思,所以,也很合乎大部分 Rails 的使用者感覺不到的原因,必竟,本來就是設計成,也希望是:不引人注目的,不張揚的。
Rails 5.1 以前,UJS 是外加的,但是 Rails 會自動幫你裝好,bundle 會有
gem 'jquery-rails'
在還就是 application.js 會有
Rails 5.1 版以後,UJS 就是內建了,而且是原生 JavaScript,不再是用 jQuery 的版本了,所以,以前很多人不喜歡它的,可以選擇不裝,現在,就如果不想用,就要「在不同的地方」,關掉它了,我是覺得 UJS 很好用啦,只是偶而會被咬到,了解它後,是好東西。
UJS 概觀
UJS 沒有什麼魔術,他分成兩半:(1) 他就是 Rails 會在某些「特定行為」中,自動在 HTML 中加入 UJS 相關的 data-* attributes,然後,(2) UJS 的 jQuery script 就會「根據」這些 data-* 來執行,聽無?來來來,免驚,下面就是 Rails tutorial 中的簡明慨念介紹,一看就懂:
在上面這個例子中,一個連結加入了 data-background-color="#000099" 跟 data-text-color="#FFFFFF" 這兩個data-* ,然後,任何 JavaScript 都可以「綁定 (bind)」這樣的 data 屬性時,去執行想做的動作,在上面這個例子中,(1) 是 Rails 的 UJS 會自動寫好上面的 HTML,(2) UJS 會綁定 JavaScript 去執行設定文字與背景顏色,這就是 UJS 的原理啦,很簡單吧,下面是原文連結,給還是看不懂人了:Working with JavaScript in Rails — Ruby on Rails Guides:
UJS 綁定哪些「特定行為」?
不多,就四大類,但是都是很常用的功能,真的可以讓開發工作省很大 (ps: 用中文說,真是難啊):
真的很想用英文寫,中文真的不好翻譯網路行為,我盡力了,知道 UJS 大概做些什麼就好了,我們來詳細看看每一個怎麼用。
1. 確認對話視窗:讓使用者按「確定」後才會執行
這個最常用的應該就是「刪除」了,Rails 用 scaffold 產生時就會自動幫忙寫好:
第一行中的
data: { confirm: "Are you sure?" }
就是讓 UJS 產生確認對話框的寫法,真是很簡單,短短兩個字:data 跟 confirm,對話框就出來了,這省了好多 JavaScript,給 UJS 拍拍手!2. 轉換「非 GET 」的動作
我們就還是用上面這個 Delete 的例子,各位看官會不會覺得很奇怪,這不是一個 link_to 嗎? Link_to 不就是一個 HTTP GET 動作嗎?怎麼會指到 controller action destroy? 沒錯,這又是 UJS 的傑作,有看到
method: :delete
解譯出data-method="delete"
嗎?哈,這又是一個 data-*,沒錯,就是它,這個就是給 UJS 下動作轉換的指令,大致上來說,UJS 的轉換如下:data-method
的連結:還有一個 remote: true 可以加在 link_to 內,任何加了 remote: true 所呼叫的 controller 動作,都會從 html 呼叫改成 js 呼叫,也就是,controller 的回應就會使用 js,簡單說,就是會由以下這個回應:
有趣的是,如果你沒有 respond_to format.js 的選項,它還是會用 respond_to html 選項走,但是這個 js 呼叫動作還繼續走下去,也就是說,下一個動作還是 remove: true,這個 bug 很不好抓,要小心。
有興趣看一下 UJS 怎麼做這個轉換動作嗎?他是用 coffee 寫的,我不喜歡 coffee... UJS method
3. 讓表單或連結做一些非同步的 Ajax 動作
Rails 提供了四個跟「Remote」有相關的 helper, 是的,你看到了關鍵字,remote,Rails 的 remote 相關 helper 都會產生一個
data-remote="true"
的 UJS 綁定 data-* ,也就是這個,讓我們在 Rails 中可以簡單的做 Ajax 網頁部分更新!那四個呢?就這四個!
這四個中,form_with 是個新玩意,Rails 5.1 以後才有,Rails 的想法是要用 form_with 取代以前的 form_for and form_tag,也就是說,Rails 希望以後所有的 form 都是 Ajax partial DOM 更新,這很有趣,為什麼?因為這意味著 Rails 未來希望更結合 UJS + Turbolinks,這兩個東西都是在 Rails 中有人愛,有人恨的東西,我想要取代的難度不低,不過,我是覺得就適應吧,時代在進步的,以前,網頁一頁一頁換,沒人嫌,現在,好多都是 single page app (SPA) 單頁式網站,說真的,SPA 的使用者體驗真的比較好,只是,開發維護都難多了。想要知道更多的 form_with? 這篇有說:
Rails 5.1's form_with vs. form_tag vs. form_for – Patrik on Rails — form_tag and form_for are soft deprecated and they will be replaced by form_with in the future. If you want to know more about form_with… Patrik on Rails
說到 SPA,Rails 的對應(戰鬥)法就是用 Server-generated JavaScript Responses (SJR) 反擊!DHH 的這篇大作,如果你還未讀,必讀啊!SJR benifits
如果您已經很熟悉 Rails 的 Ajax,恭喜,如果你還不熟,要說明它可是一個大工程,實在沒辦法在這篇寫清楚,不過它的工作方式大致如下:
escape_javascript(render @xxx)
)如果是新手,我這樣寫一定也有看沒懂,我在網上找到《捷姆斯》寫的這一篇還不錯:Rails with AJAX 範例 (使用 render js方法),寫得很詳盡,Rails 的美麗就是很棒互助的社群,幾乎各種問題都可以在網上找到解答。
等等,那第四個「其他」呢?哈!差點忘掉,哈,就是直接用 data-remote="true" + data-url + data params 來呼叫 Ajax 啦,所以是「其他」,例如下面這個例子就是用來做 checkbox Ajax 呼叫:
Form_with 這個新玩意,就是預設 data-remote="true",要關掉可以用 local: true,哇哈!又一個新玩意,以前的 form_for/form_tag 預設不是 data-remote="true",現在改成預設就是,要關掉還要另外寫,可見時代在轉變啊,真的不喜歡,可以在 config 中關掉:
如果,你還需要根據 AJAX 活動狀況做不同的動作,UJS AJAX 有提供很不錯的事件 (events) 驅動,比較會用到的是: ajax:success/complete/error,詳細就請看文件吧,不過重點是,5.1 版前與後,也就是 jQuery 與原生 JavaScript 的兩個版本的 events 是不同的,要注意! 我把這兩個版本的官網連結列在下面了:
4.防止 form submit 被「雙點擊」
在 Rails 中做一個 form 要 submit ,真是再簡單不過了:
就簡單的寫個第一行,Rails 就會產生第二行的 HTML 碼,這就是 Rails 美麗的地方,我想大部分的人都沒有真的去看產稱的 HTML 碼,但是,這次,注意一下,如果你沒看到,第二行後面 UJS 有幫你自動加了:
data-disable-with="更新文章"
咦?這是什麼東東啊?這個就是 UJS 很棒的「防雙點擊」保護,我想很多人都會在很多網路論壇上看到,同一則留言被發佈了兩次,這並不是使用者有意的,在實務上,雙點擊真的很容易產生,你如果要為每一個 submit 個別寫一個防雙點擊 JavaScript 真是很麻煩的,再說,你可以試試,要寫一個好的「防雙點擊」還不算容易的事呢。
好日子會一直到,某一天,你有一個 form 要用到 JavaScript 來驗證內容,而你又不幸的用了 onsubmit 這個最簡單的 form 驗證方法,咦?為什麼我的 form 不能 submit 了?哈,被咬到了,原來你要加入
data: { disable_with: false }
,但是為什麼?說明如下::onsubmit => "return Valid(this);"
簡單的指到那一個 JS function 去做form 驗證,傳回 true 就是沒錯,繼續 submit 動作,傳回 false 就是有錯,submit 停止,留在這個 form 上。data: { disable_with: false }
,這就是跟 UJS 說,不要給我產生「防雙點擊」保護,不加入這個,使用者只要按一次 submit,submit 就 disabled 了,也就是說,如果你的Valid()
傳會 false 說輸入有誤,使用者也不能再按 submit 了,別怕,加入data: { disable_with: false }
,就不會鎖「防雙點擊」了。data-disable-with="更新文章"
沒了,還記得“UJS 概觀”中提到的,UJS 就是用 data-* 來運作的嗎?你還可以用 UJS 來改變按下去後,Submit 按鈕的文字:
這樣,使用者按下去後,就會顯示:"更新文章中...",酷吧。
UJS 真的不錯用,當然偶而會被咬到,這也是我為什麼寫這篇文章的原因,因為我被咬很多次了啦⋯⋯ 所以這篇算是送禮自用兩相宜~
附上jQuery UJS官方網址:
rails/jquery-ujs — Ruby on Rails unobtrusive scripting adapter for jQuery - rails/jquery-ujs
GitHub