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点击提交评论,页面不刷新且在上面显示提交的评论,而且输入框内容提交后自动清空: