ruby中js接收html的值,在 Rails 中使用 JavaScript

1 Ajax 简介

在理解 Ajax 之前,要先知道 Web 浏览器常规的工作原理。

在浏览器的地址栏中输入 后,浏览器(客户端)会向服务器发起一个请求。然后浏览器处理响应,获取相关的静态资源文件,比如 JavaScript、样式表和图像,然后显示页面内容。点击链接后发生的事情也是如此:获取页面,获取静态资源,把全部内容放在一起,显示最终的网页。这个过程叫做“请求响应循环”。

JavaScript 也可以向服务器发起请求,并解析响应。而且还能更新网页中的内容。因此,JavaScript 程序员可以编写只更新部分内容的网页,而不用从服务器获取完整的页面数据。这是一种强大的技术,我们称之为 Ajax。

Rails 默认支持 CoffeeScript,后文所有的示例都用 CoffeeScript 编写。本文介绍的技术,在普通的 JavaScript 中也可以使用。

例如,下面这段 CoffeeScript 代码使用 jQuery 库发起一个 Ajax 请求:

$.ajax(url: "/test").done (html) ->

$("#results").append html

这段代码从 /test 地址上获取数据,然后把结果追加到 div#results 元素中。

Rails 内建了很多使用这种技术开发应用的功能,基本上无需自己动手编写上述代码。后文介绍 Rails 如何为开发这种应用提供协助,不过都构建在这种简单的技术之上。

2 非侵入式 JavaScript

Rails 使用一种叫做“非侵入式 JavaScript”(Unobtrusive JavaScript)的技术把 JavaScript 依附到 DOM 上。非侵入式 JavaScript 是前端开发社区推荐的做法,但有些教程可能会使用其他方式。

下面是编写 JavaScript 最简单的方式,你可能见过,这叫做“行间 JavaScript”:

Paint it red

点击链接后,链接的背景会变成红色。这种用法的问题是,如果点击链接后想执行大量 JavaScript 代码怎么办?

Paint it green

太别扭了,不是吗?我们可以把处理点击的代码定义成一个函数,用 CoffeeScript 编写如下:

@paintIt = (element, backgroundColor, textColor) ->

element.style.backgroundColor = backgroundColor

if textColor?

element.style.color = textColor

然后在页面中这么写:

Paint it red

这种方法好点儿,但是如果很多链接需要同样的效果该怎么办呢?

Paint it red

Paint it green

Paint it blue

这样非常不符合 DRY 原则。为了解决这个问题,我们可以使用“事件”。在链接上添加一个 data-* 属性,然后把处理程序绑定到拥有这个属性的点击事件上:

@paintIt = (element, backgroundColor, textColor) ->

element.style.backgroundColor = backgroundColor

if textColor?

element.style.color = textColor

$ ->

$("a[data-background-color]").click (e) ->

e.preventDefault()

backgroundColor = $(this).data("background-color")

textColor = $(this).data("text-color")

paintIt(this, backgroundColor, textColor)

Paint it red

Paint it green

Paint it blue

我们把这种方法称为“非侵入式 JavaScript”,因为 JavaScript 代码不再和 HTML 混合在一起。这样做正确分离了关注点,易于修改功能。我们可以轻易地把这种效果应用到其他链接上,只要添加相应的 data 属性即可。我们可以简化并拼接全部 JavaScript,然后在各个页面加载一个 JavaScript 文件,这样只在第一次请求时需要加载,后续请求都会直接从缓存中读取。“非侵入式 JavaScript”带来的好处太多了。

Rails 团队极力推荐使用这种方式编写 CoffeeScript(以及 JavaScript),而且你会发现很多代码库都采用了这种方式。

3 内置的辅助方法

3.1 远程元素

Rails 提供了很多视图辅助方法协助你生成 HTML,如果想在元素上实现 Ajax 效果也没问题。

因为使用的是非侵入式 JavaScript,所以 Ajax 相关的辅助方法其实分成两部分,一部分是 JavaScript 代码,一部分是 Ruby 代码。

如果没有禁用 Asset Pipeline,rails-ujs 负责提供 JavaScript 代码,常规的 Ruby 视图辅助方法负责生成 DOM 标签。

应用在处理远程元素的过程中触发的不同事件参见下文。

3.1.1 form_with

form_with 方法协助编写表单,默认假定表单使用 Ajax。如果不想使用 Ajax,把 :local 选项传给 form_with。

...

生成的 HTML 如下:

...

注意 data-remote="true" 属性,现在这个表单不会通过常规的方式提交,而是通过 Ajax 提交。

或许你并不需要一个只能填写内容的表单,而是想在表单提交成功后做些事情。为此,我们要绑定 ajax:success 事件。处理表单提交失败的程序要绑定到 ajax:error 事件上。例如:

$(document).ready ->

$("#new_article").on("ajax:success", (e, data, status, xhr) ->

$("#new_article").append xhr.responseText

).on "ajax:error", (e, xhr, status, error) ->

$("#new_article").append "

ERROR

"

显然你需要的功能比这要复杂,上面的例子只是个入门。

3.1.2 link_to

link_to 方法用于生成链接,可以指定 :remote 选项,用法如下:

生成的 HTML 如下:

an article

绑定的 Ajax 事件和 form_with 方法一样。下面举个例子。假如有一个文章列表,我们想只点击一个链接就删除所有文章。视图代码如下:

CoffeeScript 代码如下:

$ ->

$("a[data-remote]").on "ajax:success", (e, data, status, xhr) ->

alert "The article was deleted."

3.1.3 button_to

button_to 方法用于生成按钮,可以指定 :remote 选项,用法如下:

生成的 HTML 如下:

因为生成的就是一个表单,所以 form_with 的全部信息都可使用。

3.2 定制远程元素

不编写任何 JavaScript 代码,仅通过 data-remote 属性就能定制元素的行为。此外,还可以指定额外的 data- 属性。

3.2.1 data-method

链接始终发送 HTTP GET 请求。然而,如果你的应用使用 REST 架构,有些链接其实要对服务器中的数据做些操作,因此必须发送 GET 之外的请求。这个属性用于标记这类链接,明确指定使用“post”、“put”或“delete”方法。

Rails 的处理方式是,点击链接后,在文档中构建一个隐藏的表单,把表单的 action 属性的值设为链接的 href 属性值,把表单的 method 属性的值设为链接的 data-method 属性值,然后提交表单。

由于通过表单提交 GET 和 POST 之外的请求未得到浏览器的广泛支持,所以其他 HTTP 方法其实是通过 POST 发送的,意欲发送的请求在 _method 参数中指明。Rails 能自动检测并处理这种情况。

3.2.2 data-url 和 data-params

页面中有些元素并不指向任何 URL,但是却想让它们触发 Ajax 调用。为元素设定 data-url 和 data-remote 属性将向指定的 URL 发送 Ajax 请求。还可以通过 data-params 属性指定额外的参数。

例如,可以利用这一点在复选框上触发操作:

data-url="/update" data-params="id=10" data-method="put">

3.2.3 data-type

此外,在含有 data-remote 属性的元素上还可以通过 data-type 属性明确定义 Ajax 的 dataType。

3.3 确认

可以在链接和表单上添加 data-confirm 属性,让用户确认操作。呈献给用户的是 JavaScript confirm() 对话框,内容为 data-confirm 属性的值。如果用户选择“取消”,操作不会执行。

在链接上添加这个属性后,对话框在点击链接后弹出;在表单上添加这个属性后,对话框在提交时弹出。例如:

data: { confirm: 'Are you sure?' } %>

生成的 HTML 为:

Dangerous zone

在表单的提交按钮上也可以设定这个属性。这样可以根据所按的按钮定制提醒消息。此时,不能在表单元素上设定 data-confirm 属性。

默认使用的是 JavaScript 确认对话框,不过你可以定制这一行为,监听 confirm 时间,在对话框弹出之前触发。若想禁止弹出默认的对话框,让事件句柄返回 false。

3.4 自动禁用

还可以使用 disable-with 属性在提交表单的过程中禁用输入元素。这样能避免用户不小心点击两次,发送两个重复的 HTTP 请求,导致后端无法正确处理。这个属性的值是按钮处于禁用状态时显示的新值。

带有 data-method 属性的链接也可设定这个属性。

例如:

生成的表单包含:

4 处理 Ajax 事件

带 data-remote 属性的元素具有下述事件。

这些事件绑定的句柄的第一个参数始终是事件对象。下面列出的是事件对象之后的其他参数。例如,如果列出的参数是 xhr, settings,那么定义句柄时要写为 function(event, xhr, settings)。

事件名

额外参数

触发时机

ajax:before

在整个 Ajax 调用开始之前,如果被停止了,就不再调用。

ajax:beforeSend

xhr, options

在发送请求之前,如果被停止了,就不再发送。

ajax:send

xhr

发送请求时。

ajax:success

xhr, status, err

Ajax 调用结束,返回表示成功的响应时。

ajax:error

xhr, status, err

Ajax 调用结束,返回表示失败的响应时。

ajax:complete

xhr, status

Ajax 调用结束时,不管成功还是失败。

ajax:aborted:file

elements

有非空文件输入时,如果被停止了,就不再调用。

4.1 可停止的事件

如果在 ajax:before 或 ajax:beforeSend 的句柄中返回 false,不会发送 Ajax 请求。ajax:before 事件可用于在序列化之前处理表单数据。ajax:beforeSend 事件也可用于添加额外的请求首部。

如果停止 ajax:aborted:file 事件,允许浏览器通过常规方式(即不是 Ajax)提交表单这个默认行为将失效,表单根本无法提交。利用这一点可以自行实现通过 Ajax 上传文件的变通方式。

5 服务器端处理

Ajax 不仅涉及客户端,服务器端也要做处理。Ajax 请求一般不返回 HTML,而是 JSON。下面详细说明处理过程。

5.1 一个简单的例子

假设在网页中要显示一系列用户,还有一个新建用户的表单。控制器的 index 动作如下所示:

class UsersController < ApplicationController

def index

@users = User.all

@user = User.new

end

# ...

index 视图(app/views/users/index.html.erb)如下:

Users

app/views/users/_user.html.erb 局部视图的内容如下:

index 页面的上部显示用户列表,下部显示新建用户的表单。

下部的表单会调用 UsersController 的 create 动作。因为表单的 remote 选项为 true,所以发给 UsersController 的是 Ajax 请求,使用 JavaScript 处理。要想处理这个请求,控制器的 create 动作应该这么写:

# app/controllers/users_controller.rb

# ......

def create

@user = User.new(params[:user])

respond_to do |format|

if @user.save

format.html { redirect_to @user, notice: 'User was successfully created.' }

format.js

format.json { render json: @user, status: :created, location: @user }

else

format.html { render action: "new" }

format.json { render json: @user.errors, status: :unprocessable_entity }

end

end

end

注意,在 respond_to 块中使用了 format.js,这样控制器才能响应 Ajax 请求。然后还要新建 app/views/users/create.js.erb 视图文件,编写发送响应以及在客户端执行的 JavaScript 代码。

$("").appendTo("#users");

6 Turbolinks

Rails 提供了 Turbolinks 库,它使用 Ajax 渲染页面,在多数应用中可以提升页面加载速度。

6.1 Turbolinks 的工作原理

Turbolinks 为页面中所有的 元素添加一个点击事件处理程序。如果浏览器支持 PushState,Turbolinks 会发起 Ajax 请求,解析响应,然后使用响应主体替换原始页面的整个 元素。最后,使用 PushState 技术更改页面的 URL,让新页面可刷新,并且有个精美的 URL。

要想使用 Turbolinks,只需将其加入 Gemfile,然后在 app/assets/javascripts/application.js 中加入 //= require turbolinks。

如果某个链接不想使用 Turbolinks,可以在链接中添加 data-turbolinks="false" 属性:

No turbolinks here.

6.2 页面内容变更事件

编写 CoffeeScript 代码时,经常需要在页面加载时做一些事情。在 jQuery 中,我们可以这么写:

$(document).ready ->

alert "page has loaded!"

不过,Turbolinks 改变了常规的页面加载流程,不会触发这个事件。如果编写了类似上面的代码,要将其修改为:

$(document).on "turbolinks:load", ->

alert "page has loaded!"

7 其他资源

下面列出一些链接,可以帮助你进一步学习:

反馈

我们鼓励您帮助提高本指南的质量。

如果看到如何错字或错误,请反馈给我们。

您可以阅读我们的文档贡献指南。

您还可能会发现内容不完整或不是最新版本。

请添加缺失文档到 master 分支。请先确认 Edge Guides 是否已经修复。

关于用语约定,请查看Ruby on Rails 指南指导。

无论什么原因,如果你发现了问题但无法修补它,请创建 issue。

最后,欢迎到 rubyonrails-docs 邮件列表参与任何有关 Ruby on Rails 文档的讨论。

中文翻译反馈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值