Ajax介绍
为了理解Ajax, 你首先必须理解web浏览器是如何工作的
当你在你的浏览器地址中输入http://localhost:3000并按下enter时,浏览器作为客户端会给服务器端发一个请求,然后浏览器会解析response,搜集所有相关的assets,例如javascript文件、表格和图片。然后它会组合界面。当你点击一个link时,浏览器会重复上面的流程:获取page,获取assets,然后组合在一起,给你展示结果。这称为“request response cycle”。
javascript也可以给server发送请求,然后解析response。javascirpt还可以更新page上的内容。整合这两个功能,我们可以使用javascript来更新web page的部分内容,而不需要从server获取全部的内容,我们称这个技术为ajax。
下面是一个是我们使用javascript来发送ajax请求的例子:
fetch("/test")
.then((data) => data.text())
.then((html) => {
const results = document.querySelector("#results");
results.insertAdjacentHTML("beforeend", data);
});
这个代码从"/test"获取数据,然后将结果results添加到一个id为results的element之后。
Rails提供了很多内容的功能去构建web pages。通常我们不需要自己这样写代码。本文将介绍Rails如何帮助我们写这样的website。
javascript脚本
Rails使用"Unobtrusive JavaScript"技术去给dom添加javascript。如:
<a href="#" onclick="this.style.backgroundColor='#990000';event.preventDefault();">Paint it red</a>
我们可以看到,这有点类似于inline javascript
当我们点击,这个背景将变为红色。当我们希望click触发很多类似操作时,我们则需要将onclick的handler的函数定义真正的转化为一个函数,如下:
window.paintIt = function(event, backgroundColor, textColor) {
event.preventDefault();
event.target.style.backgroundColor = backgroundColor;
if (textColor) {
event.target.style.color = textColor;
}
}
然后在我们的界面,可以如下使用:
<a href="#" onclick="paintIt(event, '#990000')">Paint it red</a>
而当我们需要重复许多类似的操作时,如下:
<a href="#" onclick="paintIt(event, '#990000')">Paint it red</a>
<a href="#" onclick="paintIt(event, '#009900', '#FFFFFF')">Paint it green</a>
<a href="#" onclick="paintIt(event, '#000099', '#FFFFFF')">Paint it blue</a>
则我们可以使用events来进行优化。我们可以给我们的link增加‘data-*’属性,然后给每一个拥有这个属性的link绑定click event的handler。如下:
function paintIt(element, backgroundColor, textColor) {
element.style.backgroundColor = backgroundColor;
if (textColor) {
element.style.color = textColor;
}
}
window.addEventListener("load", () => {
const links = document.querySelectorAll(
"a[data-background-color]"
);
links.forEach((element) => {
element.addEventListener("click", (event) => {
event.preventDefault();
const {backgroundColor, textColor} = element.dataset;
paintIt(element, backgroundColor, textColor);
});
});
});
则我们就可以进行如下操作:
<a href="#" data-background-color="#990000">Paint it red</a>
<a href="#" data-background-color="#009900" data-text-color="#FFFFFF">Paint it green</a>
<a href="#" data-background-color="#000099" data-text-color="#FFFFFF">Paint it blue</a>
我们管它叫'unobtrusive' JavaScript是因为我们从此不再需要将javascript和html混合在一起。这样做的好处是:我们很好的维护我们的脚本。我们可以很方面的给link添加data的属性并添加相应的行为。
内置的helpers
远端的元素
Rails提供了一系列的view helper方法帮我们生成html。因此,'unobtrusive' JavaScript分为:javascirpt half 和ruby half。
我们主要讲解rails javascript half。
form_with
form_with是帮助我们生成forms的helper。为了使用ajax,我们需要设置local=false。如下:
<%= form_with(model: @article, id: "new-article", local: false) do |form| %>
...
<% end %>
则会生成如下html,
<form id="new-article" action="/articles" accept-charset="UTF-8" method="post" data-remote="true">
...
</form>
当data-remote="true"时,这个form会异步提交。我们可以绑定ajax:success/ajax:error给这个event。如下:
window.addEventListener("load", () => {
const element = document.querySelector("#new-article");
element.addEventListener("ajax:success", (event) => {
const [_data, _status, xhr] = event.detail;
element.insertAdjacentHTML("beforeend", xhr.responseText);
});
element.addEventListener("ajax:error", () => {
element.insertAdjacentHTML("beforeend", "<p>ERROR</p>");
});
});
link_to是帮助我们生成links的helper。其也有:remote选项,我们可以如下使用:link_to
<%= link_to "an article", @article, remote: true %>
生成为:
<a href="/articles/1" data-remote="true">an article</a>
我们可以绑定向form_with一样的异步操作。我们假设我们有一长串的文件,通过一个link就可以全部删除。我们可以生成如下html。
<%= link_to "Delete article", @article, remote: true, method: :delete %>
然后如下写javascript
window.addEventListener("load", () => {
const links = document.querySelectorAll("a[data-remote]");
links.forEach((element) => {
element.addEventListener("ajax:success", () => {
alert("The article was deleted.");
});
});
});