啥是 RJS ?Ajax 使用户与浏览器之间的交互体验更像是桌面程序。因为 Ajax 允许浏览器在后台发起远程调用。这些请求可以在无刷新的情况下更新当前页面。Ruby on Rails 框架内置对 Ajax 有极好的支持。Rails 1.0 支持基于 Ajax 的远程 JavaScript (RJS) 模板,将来,还允许你更新多个页面的元素。
RJS 模板是 Rails 1.1 增加的一个强大的功能。不同于其他的 Rails 那些需要渲染然后发送给浏览器的模板,RJS 模板用来更新那些已经被渲染过的页面。
Rails 1.1 之前,已经允许通过 Ajax 调用来更新单一页面的元素。可是,当你想更新多个页面的元素却很难。RJS 允许你在一个 Ajax 调用中使用 Ruby 代码更新多个页面的元素. 你可以在一个模板中使用许多 Script.aculo.us 提供的视觉效果,并且你根本不需要写任何 JavaScript。在大部分案例中,不再需要在 JavaScript 转换内容和程序。所有的 JavaScript 都由 Rails JavaScript Generator 产生, Ajax 响应由 prototype 库自动得到。
如你所知,RJS 让更新多个页面的元素和通过一个 Ajax 调用产生多个页面效果变的更简单。
下面开始一个简单的介绍性的例子。我把这个应用命名为 "Thought Log"。 Thought Log 简单的获取文本框输入的数据并在无刷新的情况下把他记入当前页面。首先创建这个应用。
cody> rails thought_log
现在新建一个 controller,ThoughtsController,用来保存我们的 actions。
cody> ruby script/generate controller Thoughts
exists app/controllers/
exists app/helpers/
create app/views/thoughts
create test/functional/
create app/controllers/thoughts_controller.rb
create test/functional/thoughts_controller_test.rb
create app/helpers/thoughts_helper.rb
发生器创建了 controller,helper 并为 controller 的视图创建了一个文件夹。现在我们增加两个 action。第一个 action 名为 index(), 显示最初的空的 thoughts 的列表。第二个 action 名为 log(),在后台调用 Ajax 并将新的 thought 增加到当前页面。
class ThoughtsController < ApplicationController
def index
end
def log
@thought = params[:thought]
end
end
log() action 简单的将值 params[:thought] 赋给实例变量 @thought 然后渲染 app/views/thoughts/log.rjs 模板。我们根据 Rails 的约定, controller 默认渲染和 action 同名的模板。既然 .rjs 模板也是另一个模板,Rails 在 controller 的视图文件夹去寻找 log.rjs 模板。唯一的缺点是在视图文件夹下有同名的模板,Rails 会在渲染 .rjs 模板之前先渲染 .rhtml 和 .rxml。在 Rails 下相当于:
def log
end
def log
render :action => 'log'
end
其实你不必声明 index() action,Rails 默认就会调用 index() action 并渲染该控制器视图文件夹下的 index.rhtml 模板文件。
RJS 模板依靠 prototype.js JavaScript 库。如果你希望使用 Script.aculo.us 视觉效果和控制器,你也需要 effects.js,controls.js 和 dragdrop.js。你可以在项目中在视图中增加 javascript_include_tag :defaults。这个也会把 application.js 文件载入进来。
接下来我们创建最初的视图。这个页面创建远程 Ajax 调用。通常你要为应用创建一个布局,但是因为这个例子是只有一个页面,我们把一切都放到视图模板中。在 app/views/thoughts 文件夹中创建 index.rhtml。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Thought Log</title>
<%= javascript_include_tag :defaults %>
</head>
<body>
<h1>My thoughts</h1>
<% form_remote_tag :url => { :action => 'log' }, :html => { :id => 'thought-form' } do %>
<%= text_field_tag 'thought', nil, :size => 40 %>
<%= submit_tag 'Log thought' %>
<%= end %>
<div id="thoughts"></div>
</body>
</html>
使用 javascript_include_tag 这个辅助方法,来包含 Rails 中所需要的 JavaScript 库是很简单的。辅助方法后面跟随符号 :defaults 会调用 Rails 中的全部 JavaScript 库,包括你自己编写的 application.js,如果它存在的话。
在引入必须的 JavaScript 文件后, 我们创建一个仅含有一个文本输入框的简单的表单。我们不使用 form_tag() 辅助方法,而使用 form_remote_tag() 辅助方法。两者不同的是 form_remote_tag() 在后台使用 Ajax 来更新表单和提交数据,而不是像 form_tag() 重新渲染页面。参数 :url 指定控制器中收取表单数据的 action。这里,我们把数据提交给当前控制器 ThoughtsController 中的 log() action。我们通过 :html 选项来给表单增加一个 id。 这允许我们通过 RJS 模板在完成提交动作后重置表单。
最后,视图有一个 id 是 thoughts 的空的 <div> 元素。id 让我们可以通过 RJS 模板来更新页面元素。thoughts <div> 是一个容器用来包含表单提交的数据。接下来,我们终于要创建实际的 RJS 模板,你可以看看一切是怎么结合起来的。
现在在做主要的视图之前,我们需要一个小的局部模板来绘制 logged thoughts。局部模板让 RJS 模板保持干净和简单。创建局部模板 app/views/thoughts/_thought.rhtml 并填入下面的代码。
<p>
<span style="font-size: 0.8em;">[<%= Time.now.to_s(:db) %>]</span>
<%=h thought %>
</p>
这个局部模板很简单。它只是在一个段落中显示当前时间和 logged thought。这里有一个很棒的习惯做法,使用 h() 来格式化用户输入的文本,避免页面执行其中一些不需要的脚本。
在使用 RJS 模板执行远程调用的时候绝对不要使用 :update 选项。 :update 选项通知 Rails 产生一个 Ajax.Updater Prototype 对象 而不是 Ajax.Request 对象。Ajax.Updater 使用返回的 HTML 来更新单一的 DOM 元素。RJS 模板返回 JavaScript 给浏览器,来产生我们希望得到的效果。
最后,创建 RJS 模板,我们遵守 Rails 约定,把视图的名字和 action 的保持一致。这样我们就不需要在控制器中明确的声明 render()。创建 app/views/thoughts/log.rjs 并填入随后的代码。
page.insert_html :bottom, 'thoughts', :partial => 'thought'
page.visual_effect :highlight, 'thoughts'
page.form.reset 'thought-form'
首先,这个 page 对象从哪来滴?page 对象实际上是一个 Rails 的 JavaScriptGenerator 实例,它产生全部 JavaScript 并传递给浏览器。所有的 RJS 方法都在这个page 对象上调用。下一章我们将仔细分析 RJS 模板在 Rails 中的处理方法。
既然我们在后台已经有了少量的 page 对象,我们可以考虑模板中的个别调用。首先,局部模板 app/views/thoughts/_thought.rhtml 会被渲染,产生的结果插入 thoughts <div> 的最下面。第一个参数是插入新内容的位置,我们可以有4个选项,包括 :before, :after, :bottom 和 :top。 第二个参数指定 DOM 元素的 id,内容插入其中。第三个参数可以是字符串或hash参数来调用 ActionView#render()。通过参数 :partialto 你可以用局部模板输出的内容来修改 DOM 元素,或者通过 :inline 参数使用内部模板。每次新的 thought logged 出现在所有以前存在的 logged thoughts 之后。
接下来一个黄退的视觉效果应用在 thoughts <div>。visual_effect() 方法接受第三个参数是一个hash。最后,一个 RJS 类 proxy 用来重置表单,proxying 调用 Prototype 静态表单的辅助方法 Form.reset() 并传递给它表单的id。下一章我们会详细讨论proxies。
© Railser.cn 里克的网络自习室,仅供学习参考,更新于2008年3月23日