1 An Introduction to Ajax
打开网页的的过程也叫:request response cycel。
JavaScript也可以request然后parse the response,还可以更新网页上的信息。
因此JS可以部分更新网页。这个技术称为Ajax.
Rails默认使用CoffeeScript。包括应用JS.例子:
$.ajax(url: "/test").done (html) ->
$("#results").append html
这段代表从url上取数据,然后附加到一个id为results的div后面。
Rails 提供了内建支持来使用这个技术开发网页。无需你自己写这样的代码。有helper方法。
基本原理就是这样。
2 Unobtrusive JavaScript 不冒失的JS
Rails使用这个技术来把JS附加到DOM上去。unobtrusive意味着不把JS代表混入到HTML。
而是用data-*属性来传递参数给behavior。
3 Built-in Helpers
3.1 Remote elements
Rails提供了一组视图帮助方法,是用Ruby写的,用于帮你生成HTML元素。有时,你要增加Ajax到那些元素中。
因为Unobtrusive JS, the Rails "Ajax helper"其实一半是Ruby一半是JS。
rails-ujs提供了JS的部分,Ruby view helper增加适当的tags到你的DOM。
3.1.1 form_with
form_with默认生成data-remote= "true",可以绑定事件:
$(document).ready ->
$("#new_article").on("ajax:success", (event) ->
[data, status, xhr] = event.detail
$("#new_article").append xhr.responseText
).on "ajax:error", (event) ->
$("#new_article").append "<p>ERROR</p>"
解释:如果成功了则。。。,如果失败了则附加一个<p>
3.1.2 link_to
link_to 添加remote: true,后生成data-remote= "true",我们可以绑定Ajax events.如:
$ ->
$("a[data-remote]").on "ajax:success", (event) ->
alert "The article was deleted."
另外button_to 实际生成一个<form><input>...表格。
3.2 Customize remote elements
使用data-remote 属性无需再写一行jS代码,就能客制化元素的行为。你可以指定额外的 data-attributes来完成它。
3.2.1 data-method
就是RESTful风格,可以用HTTP的4个事件来激活link。
3.2.2 data-url
and data-params
某个元素不涉及任何URL, 但你想要它们trigger Ajax calls。需要一起使用data-url和data-remote,另外还可以用data-params增加额外的参数。
如选项框:checkbox
<input type="checkbox" data-remote="true"
data-url="/update" data-params="id=10" data-method="put">
3.2.3 data-type
data-type
attribute.
3.3 其他:
data-confirm属性:
link_to "Dangerous zone", *_path, data: { confirm: "Are you sure?"} 生成类似:
<a href="..." data-confirm="Are you sure?">Dangerous zone</a>
data-disable-with
attribute:
<%= form_with(model: @article.new) do |f| %>
<%= f.submit data: { "disable-with": "Saving..." } %>
<%= end %>
生成:<input data-disable-with="Saving..." type="submit">
3.5 Rails-ujs event handlers(点击见,变化的event表格)
Rails5.1介绍rails-ujs,并且无需依赖jQuery。新版所有custom events只返回一个参数event.
增加了一个event.detail属性,它会返回一个array,这个array包括了其他的参数xhr, options, response, status。
Event name | Extra parameters (event.detail) | Fired |
---|---|---|
ajax:success |
[response, status, xhr] | 在完成后,如果response是success,则激活event |
例子:
document.body.addEventListener('ajax:success', function(event) {
var detail = event.detail;
var data = detail[0], status = detail[1], xhr = detail[2];
})
补充EventTarget.addEventListener()方法:
将指定的监听器注册到EventTarget上,当该对象出发指定的事件时,指定的回调函数就会被执行。target.addEventListener(type, listener, options)
在上面的例子'ajax:success'就是一个事件,后面的function是监听器。一旦事件触发,就会执行函数。结果返回给body.
4 Server-Side Concerns
Ajax除了客户端需要设置,服务器端也需要设置来支持它。通常,开发者想要Ajax request 返回JSON而不是HTML。看看怎么做:
4.1 案例http://guides.rubyonrails.org/working_with_javascript_in_rails.html#a-simple-example
或者参考:
file:///Users/chentianwei/离线保存的全栈文件/学习中心%20新生大学全栈营/Content/954.html
重点:
在create方法内加 format.js, 添加create.js.erb文件。
然后使用escape_javascript(javascript)方法,也可以使用别名 j(),它的作用是转化为可以识别的javsscript代码。
下面2句code作用相同:
$("#post-list").prepend("<%=j render :partial => "post", :locals => { :post => @post } %>");
$("<%= escape_javascript(render :partial => "post", :locals => { :post => @post }) %>").prependTo("#post-list");
常用的vanilla javascript方法 替代jquery
其实是一个joke的叫法,准确的说是plain, regular javascript.
valla是一种俚语,意思是太常见以至于被认为是unexciting/normal/boring. 所以Vanllia JS实际上的意思是Normal Javascript。就像一个普通的vanilla icecream without topping。
(视频), 比jquery快100倍。
- How to do queries for elements on the page.
- How to add events.
- How to hide/show just like you do with jQuery.
- and so on...
在chrome的inspect-console可以输入JS查询,得到对应的web element.
document.querySelector("#notifications")
<div id="notifications">…</div>
document.getElementById("notifications")
<div id="notifications">…</div>
document.getElementsByTagName("a")
HTMLCollection(8) [a, a, a, a, a, a, a, a]
document.querySelectorAll("#notifications p")
返回匹配元素的NodeList,这是一个array,可以使用array的方法, 如果是空的,则没有找到匹配。
NodeList(4) [p#notification_1, p#notification_2, p#notification_3, p#notification_4]
jquery和使用vanilla javascript的区别:
$("a").on("click", function(){ }) #无论你在function中运行什么都行,比如循环
而原生js必须明确指定循环操作:
VM16935:2 Uncaught TypeError: Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only 1 present.
document.querySelectorAll("p").forEach(function(anchor) {
anchor.addEventListener("click", function(event) {
event.preventDefault();
console.log("clicked");
})
})
> undefined #如果点击网页上的任意p元素,则出现:
> clicked
⚠️ Array.prototype.forEach()方法执行一个提供的函数对每一个array element。
jquery的show, hide
$("#notifications").show/hide等同于:
document.querySelector("#notifications").style.display = 'none'
>"none"
document.querySelector("#notifications").style.display = 'block'
>"block"
document.querySelector("p").style
>CSSStyleDeclaration {alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: "", …}
点击css,会弹出所有可以使用的style后的css。是使用驼峰写法的,根原生css有区别:
css: body {background-color: red; }
JS: backgroundColor: "red";
jquery的append
$("#notifications").append("<p>Test</p>") ,等同于:
node = document.createRange().createContextualFragment("<p>test</p>")
#document-fragment<p>test</p>
document.querySelector("#notifications").appendChild(node)
⚠️:有几个知识点:
- createRange(): 创建一个Range object
- Range.createContextualFragment(tagString): 创建一个text和tags然后被转化为doucment fragment
- appendChild(node): 放置到焦点元素的子元素的最后。 (点击查看Node 知识点,之前博客)
抓取attributes和Data
<a rel="nofollow" data-method="delete" href="/users/sign_out">登出</a>
$("a").data("method")
> "delete"
$("a").attr("href")
>"/users/sign_out"
使用原生的:
document.querySelector("a").dataset
> DOMStringMap {method: "delete"}
document.querySelector("a").dataset.method = "post" #可以改变
> "post"
另外一种原生写法:
document.querySelector("a").attributes, #attributes获得所有属性。
>NamedNodeMap {0: rel, 1: data-method, 2: href, rel: rel, data-method: data-method, href: href, length: 3}
document.querySelector("a").getAttribute("data-method")
> "delete"
Ajax requests
用jquery version这么写: $.ajax({ })
Rails.5.1 这么写:(Javascript version with Rails UJS)
这会自动包括你的CSRF token for non-GET requests as well。❓啥意思
csrf token是一个校验随机数,用于防止cross-site request forgery跨站请求伪装攻击。
Rails.ajax({
url: "/notificaitons.json",
type: "GET",
success: function(data) {
console.log(data)
}
})
⚠️ 视频:Rails5.1 new UJS library的使用
使用turbolinks,目的:放置到页面上面,等待HTML加载完成后,再加载
$(document).on("turbolinks:load", function() { ... }), 可以改成javascritp version:
document.addEventListener("turbolinks:load", function() { ... })
原生javascript 转化为coffeescript (点击,进入自动转化网站)
document.addEventListener("turbolinks:load", function() {
document.getElementById("new_message").addEventListener("keypress", function(e){
console.log(e.key)
})
})
转化为:
document.addEventListener 'turbolinks:load', ->
document.getElementById('new_message').addEventListener 'keypress', (e) ->
console.log e.key
return
return
jquery和原生js的相同功能代码( slim结构 ):
功能:删除一个贴文:
$(document).on("turbolinks:load", function(){
$(".delete-post").click(function(evt){
// 只能终止刷新index后的行为。
evt.preventDefault();
var url = $(this).attr("href");
$.ajax({
url: url,
method: 'DELETE',
dataType: 'json',
success: function(data){
$("#post-" + data["id"]).remove();
}
})
// 也有preventDefault()的作用
// return false
})
})
document.addEventListener("turbolinks:load", function() {
document.querySelectorAll(".delete-post").forEach(function(anchor) {
anchor.addEventListener("click", function(event) {
event.preventDefault();
var url = this.getAttribute("href");
Rails.ajax({
url: url,
type: "DELETE",
dataType: 'json',
success: function(data) {
document.getElementById("post-" + data["id"]).style.display = 'none'
}
})
})
})
})
解释:
蓝色:放置在页面顶部 放置到页面上面,等待HTML加载完成后,再加载
绿色:主要区别。
黄色:写法的完全区别。
错误❌:新增的贴文,页面必须从新加载一次,否则点击删除按钮,会自动跳转到show页面
Turbolinks(6600🌟)
https://github.com/turbolinks/turbolinks
使用Ajax加速网页渲染。
RubyonRails
1.add gem 'turbolinks', '~> 5.1.0', 然后bundle install
2.add //= require turbolinks到application.js文件中。
如何使用:Page change Events
$(document).on "trubolinks:load", -> alert "page has loaded!"
更多使用方法见git
来源:oschina
链接:https://my.oschina.net/u/4403077/blog/3910395