Ajax就是前端頁面經過js向後端服務器請求資源,服務器返回資源給前端頁面,前端頁面獲得js資源並自動執行呈如今瀏覽器頁面。這種方式下,頁面獲取服務器資源並呈現新增長的內容,然而頁面你看不到刷新的痕跡,並且也不會像刷新頁面那樣又返回頁面頂部。 javascript
我們仍是來看這個評論框,如今若是提交評論,那頁面會整個刷新,因而會跳到頁頂,用戶體驗很差。 html
點擊"提交評論"以後整個頁面刷新(頁面會閃一下)並來到頁面頂部: 前端
原來代碼: java
修改後的代碼: jquery
而後咱們刷新頁面查看源碼,發現跟原來的區別就是在原來的基礎上添加了一個data-remote="true" ajax
這樣轉換成的 html 其實變化不大,就是多了 data-remote="true" 這幾個字,可是注意在 application.js 文件中 有 require jquery_ujs,rails默認就加載了 jquery_ujs 這個 js 文件,裏面的代碼會把remote: true的表單提交自動變成一次異步的 ajax 提交。具體細節不用管,真正要關心的就是後臺 log 中的變化。若是出現Processing by IssuesController#show as JS (非 ajax 請求是請求 html) 證實前端要作的修改就弄好了。 後端
而後咱們從新在頁面提交評論: 瀏覽器
在控制檯日誌中能夠看到以js方式提交了表單(ajax就是用javascript向服務器提交數據),也就是實現了ajax: ruby
由於提交給後端的create動做,用respond_to方法設置JS格式的響應,而且在與該控制器create動做對應views目錄下位置建立js代碼--這樣rails收到請求才知道去哪裏查找js文件,修改以下代碼: 服務器
而後建立 app/views/comments/create.js (先新建comments目錄)注意這樣位置不能敲錯,否則 rails 就找不着這個文件了(由於提交給後端的comment控制器的create動做,因此對應的ajax的javascript代碼位置在views/comments目錄下,文件名與動做名一致)。
先在裏面寫個 alert("hello"); 這樣在前端提交一下評論,就能夠看到後端給發送過來 create.js 的內容,並在瀏覽器裏執行了。好,這就是基本流程,挺簡單吧。
點擊"提交評論",這樣前端就會向後端服務器請求javascript的資源,後端響應請求就把javascript的資源(也就是咱們定義的create.js文件裏的代碼)傳遞給前端瀏覽器並在瀏覽器中執行,效果以下:
如上就是是最簡單的ajax,體現了ajax的完整工做流程。
固然咱們要作的不是打印hello,而是要在評論列表的最底部追加一條評論,而這裏要添加的內容就是一些比較複雜的html了,直接都寫在create.js文件不太好,我這麼作:
可是直接render模板,由於視圖模板裏面的引號和換行符直接render會致使javascript的語法錯誤,可使用rails的接口escape_javascript 把 視圖模板中的引號和回車進行轉義;該接口函數能夠簡寫爲一個字母j。以下:
因此咱們把顯示所有評論的_commit_list.html.erb重命名爲_commit.html.erb就能夠了(博客的show頁面裏面使用_commit_list.html.erb局部模板,使用ajax以後咱們後面會把渲染_commit_list.html.erb獲得所有評論改爲使用each遍歷渲染每一個_commit.html.erb即每一個評論視圖模板達到同樣的效果),以下:
補充:上面那樣變成渲染局部模板_commit.html.erb會讓人感受這跟前面學習的視圖部分同樣了,跟ajax沒有關係了吧。其實不是,這裏渲染局部模板的代碼放在create.js.erb文件而且用escape_javascript 把 視圖模板中的引號和回車進行轉義成js資源了,因此每當提交新的評論是想服務器請求這個js資源,因此這就是ajax,不是之前的渲染視圖。點擊提交按鈕,create.js.erb文件中的js資源都會被返回,也就是返回一個彈出框顯示hello,而且返回渲染的評論局部模板。
由於每點擊一次提交按鈕就獲得create.js.erb裏的所有js資源,咱們但願每次提交獲得一條新評論的局部模板,因此這個create.js.erb裏面是渲染單條評論的局部模板;若是仍是_comment_list.erb那麼結果將是每次提交一條評論,show頁面視圖多出一遍所有評論,雖然頁面也是沒刷新的ajax方式,可是頁面已經顯示所有評論了,咱們只想頁面添加新提交的評論而已不是添加所有評論。
因此_commit.html.erb視圖代碼裏面改爲只渲染一條評論:
在來到博客的show頁面(也就是上面咱們的那個頁面),咱們找到包裹評論的div,發現評論框也在裏面:
更改成:
把評論框的局部視圖移動到評論列表的div下面,防止新添加的評論顯示在評論框下面。
由於如今沒有_comment_list.html.erb了,因此show頁面只能遍歷每一個_comment.html.erb來顯示所有評論
注意咱們在上面create.js.erb中渲染js資源爲每條評論的局部視圖那時就已經完成ajax的所有代碼了,以下就是跟ajax無關了,就是最普通的渲染局部視圖而已。當咱們點擊提交按鈕,跟show頁面的渲染局部視圖沒有任何關係也就是跟下圖代碼沒有關係:
頁面新呈現的代碼不是上面each多渲染一個評論視圖獲得的,而是跟最開始獲取hello彈出框同樣從create.js.erb的js資源中獲得的
(1)
普通的渲染方式---show.html.erb中each方法渲染每一個評論的局部視圖,咱們傳遞給它一個局部變量c(c用each獲得的實例變量賦值),使得該局部視圖無對應的動做實例變量也可以使用該變量。以下的局部變量c是@comments.each do |c|中的c獲得的
(2)
Ajax的渲染方式---show頁面中局部視圖裏_comment_box.html.erb中form_for標籤添加 remote: true(由於提交給動做是create動做因此找到對應的create.js.erb的js資源文件,該文件中的局部視圖須要使用評論變量因此也要傳遞進來這個局部變量)
原來:
修改成:
由於_comment,html.erb中使用了局部變量c,而_comment.html.erb是局部視圖無對應動做實例變量可用。
方式一:
咱們就想到comments控制器的其餘視圖可使用實例變量,咱們能夠在comments控制器對應動做的視圖中將該實例變量傳遞給改局部模板(該動做視圖也是相似,就是該動做視圖也須要加載該局部模板),不過comments控制器只有create動做,因此這個方式行不通。
方式二:
這裏create.js.erb對應的就是comments的create動做,能夠在create.js.erb使用實例變量。咱們沒法經過其餘動做視圖將實例變量賦值給局部變量,而後再將局部變量傳遞給局部模板使用,那麼此時能夠經過create.js.erb將實例變量賦值給局部變量,而後再將局部變量傳遞給局部模板使用來完成。
create.js.erb要使用實例變量,因此控制器動做改爲實例變量
修改成:
而後咱們查看效果,輸入222點擊提交以後,頁面沒有刷新而且在上方顯示提交的評論
可是咱們但願提交以後輸入框的222清空,而且不但願保留原來彈出的提示框顯示hello,因而修改create.js.erb爲以下:
再來試一下,輸入eee點擊提交評論,頁面不刷新且在上面顯示提交的評論,而且輸入框內容提交後自動清空: