AJAX完全依赖于XMLHttpRequest对象
GET请求
// 创建xhr对象 var xhr = new XMLHttpRequest(); // 监听xhr对象 xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { console.log(xhr.responseText); } } } xhr.open("get", URL) xhr.send(null)
这里监听要写在send之前,先监听后向服务器发起请求,相反如果请求发出在监听则本末倒置,即便在开发上并无区别。
xhr对象一旦开始open,就有了readyState属性,readyState属性一旦发生改变,就能够触发onreadystatechange事件,所以要先监听,这也是所有轮子的标准模板。
在open时http请求并没有发出,直到send后才会发出。
readyState 状态
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
我们只会关心就绪状态为4时
浏览器执行到Ajax代码,发出了一个HTTP请求,欲请求服务器上的数据服务器的此时开始I/O,所谓的I/O就是磁盘读取,需要花一些时间,所以不会立即产生下行HTTP报文。
由于Ajax是异步的,所以本地的JavaScript程序不会停止运行,页面不会假死,不会傻等下行HTTP报文的出现。后面的JavaScript语句将继续运行。进程不阻塞。
服务器I/O结束,将下行HTTP报文发送到本地。
如果时post请求必须手动设置请求头,模拟form表单提交
xhr.open("post", URL)
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("name=" + encodeURIComponent("夏彬"))
这里尽量将中文转译,防止服务器错乱,后台程序语言,都能够自动处理转译。
每个XMLHttpRequest对象只能监听一条HTTP请求,直到这条请求结束,才能发起下一条,强行发起上一条请求会被注销。
因为同源策略所以XMLHttpRequest对象是不能跨域的,我们可以使用JSONP来跨域,JSON+Padding,用一种逆思维来跨域
fun({ "result" : [ { "name" : "小明", "age" : 12, "sex" : "男" }, { "name" : "小红", "age" : 13, "sex" : "女" }, { "name" : "小绿", "age" : 16, "sex" : "女" } ] });
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function fun(data) {
console.log(data)
}
</script>
<script src="jsonp.txt"></script>
</body>
</html>
我们可以将JSONP封装为轮子以达到正向编程的目的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
jsonp('jsonp.txt', "name=xiabin", "fun", function(data) {
console.log(data)
})
function jsonp(URL, queryString, callbackName, callback) {
// 将JSONP定义函数绑定到window上
window[callbackName] = callback;
var dom = document.createElement('script');
dom.src = queryString ? URL + "?m=" + Math.random() + "&" + queryString : URL + "?m=" + Math.random();
document.body.appendChild(dom)
document.body.removeChild(dom);
}
</script>
</body>
</html>
当然如果一些数据不同源,且返回的不是JSONP数据,那么我们仍然可以使用服务器语言进行偷数据,现在很多网站都防偷。。。
例如:PHP中
<?php header("Content-Type:text/json;charset=gb2312"); $phone = $_GET["phone"]; $a = file_get_contents("http://chongzhi.jd.com/json/order/search_searchPhone.action?mobile=".$phone); print_r($a); ?>
例:AJAX实现瀑布流两种算法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
body {
background-color: #ccc;
}
.waterfall {
790px;
margin: 0 auto;
position: relative;
}
.grid {
position: absolute;
230px;
background-color: white;
padding: 10px;
border-radius: 15px;
}
.grid img {
230px;
}
.grid .title {
font-weight: bold;
font-size: 18px;
line-height: 32px;
}
.grid .neirong {
line-height: 150%;
font-size: 14px;
margin-bottom: 20px;
}
.grid .zuozhe {
float: right;
color: orange;
font-size: 12px;
}
.loading {
margin: 0 auto;
400px;
line-height: 30px;
text-align: center;
font-size: 14px;
background-color: gold;
color: white;
}
</style>
</head>
<body>
<div class="waterfall" id="waterfall">
</div>
<div class="loading">
正在加载...
</div>
<script type="text/template" id="grid_template">
<div class="grid">
<img src="<%=imgurl%>" alt="" />
<p class="title">
<%=title%>
</p>
<p class="neirong">
<%=content%>
</p>
<p class="zuozhe">
<%=author%>
</p>
</div>
</script>
<script src="js/jquery-1.12.3.min.js"></script>
<script src="js/underscore.js"></script>
<script>
var container = document.getElementById("waterfall");
var templateStr = document.getElementById("grid_template").innerHTML;
var $loading = $(".loading");
// 生成数据绑定函数
var template = _.template(templateStr);
gotoPage(1)
// AJAX数据请求函数
function gotoPage(num) {
$loading.hide();
$.get("json/json" + num + ".txt", function(data) {
data = JSON.parse(data);
// 没有数据则直接退出
console.log(data.news)
if (data.news.length == 0) {
$loading.show().html("没有更多了");
return;
}
_.each(data.news, function(dictionary) {
var IMG = new Image();
IMG.src = dictionary.imgurl;
// 那张图先加载完渲染那张
$(IMG).load(function() {
var templateStr = template(dictionary);
var $grid = $(templateStr);
var top = 0;
$(container).append($grid);
// 计算位置
for (var i = $grid.index() - 3; i >= 0; i -= 3) {
top += $(".grid").eq(i).outerHeight() + 20;
}
$grid.css({
"left": $grid.index() % 3 * 270,
"top": top
})
$(container).height($(document).height())
$loading.hide();
})
})
lock = true;
})
}
var lock = true;
// 页面滚动加载流
var page = 0;
$(window).scroll(function() {
if (!lock) return;
var ratio = $(window).scrollTop() / ($(document).height() - $(window).height());
if (ratio > 0.7) {
lock = false;
page++
gotoPage(page)
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
body {
background-color: #ccc;
}
.waterfall {
790px;
margin: 0 auto;
position: relative;
}
.grid {
position: absolute;
230px;
background-color: white;
padding: 10px;
border-radius: 15px;
}
.grid img {
230px;
}
.grid .title {
font-weight: bold;
font-size: 18px;
line-height: 32px;
}
.grid .neirong {
line-height: 150%;
font-size: 14px;
margin-bottom: 20px;
}
.grid .zuozhe {
float: right;
color: orange;
font-size: 12px;
}
.loading {
margin: 0 auto;
400px;
line-height: 30px;
text-align: center;
font-size: 14px;
background-color: gold;
color: white;
}
</style>
</head>
<body>
<div class="waterfall" id="waterfall">
</div>
<div class="loading">
正在加载...
</div>
<script type="text/template" id="grid_template">
<div class="grid">
<img src="<%=imgurl%>" alt="" />
<p class="title">
<%=title%>
</p>
<p class="neirong">
<%=content%>
</p>
<p class="zuozhe">
<%=author%>
</p>
</div>
</script>
<script src="js/jquery-1.12.3.min.js"></script>
<script src="js/underscore.js"></script>
<script>
var container = document.getElementById("waterfall");
var templateStr = document.getElementById("grid_template").innerHTML;
var $loading = $(".loading");
// 生成数据绑定函数
var template = _.template(templateStr);
// 位置数组
var positionArr = [0, 0, 0];
gotoPage(1)
// AJAX数据请求函数
function gotoPage(num) {
$loading.hide();
$.get("json/json" + num + ".txt", function(data) {
data = JSON.parse(data);
// 没有数据则直接退出
console.log(data.news)
if (data.news.length == 0) {
$loading.show().html("没有更多了");
return;
}
_.each(data.news, function(dictionary) {
var IMG = new Image();
IMG.src = dictionary.imgurl;
// 那张图先加载完渲染那张
$(IMG).load(function() {
var templateStr = template(dictionary);
var $grid = $(templateStr);
var minValue = _.min(positionArr);
var index = _.indexOf(positionArr, minValue);
$(container).append($grid);
$grid.css({
"left": index * 270,
"top": minValue,
})
positionArr[index] += $grid.innerHeight() + 20;
$(container).height($(document).height())
$loading.hide();
})
})
lock = true;
})
}
var lock = true;
// 页面滚动加载流
var page = 0;
$(window).scroll(function() {
if (!lock) return;
var ratio = $(window).scrollTop() / ($(document).height() - $(window).height());
if (ratio > 0.7) {
lock = false;
page++
gotoPage(page)
}
})
</script>
</body>
</html>
百度招聘分页查询
<!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" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Document</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
body {
background-color: #ccc;
}
.content {
background-color: white;
1100px;
margin: 0 auto;
font-size: 12px;
padding: 20px;
}
.content .jobtable {
position: relative;
}
.content .row {
overflow: hidden;
line-height: 40px;
position: relative;
}
.content .hd {
font-weight: bold;
}
.content .row .cols {
overflow: hidden;
position: relative;
border-bottom: 1px solid #ccc;
}
.content .row .col {
float: left;
}
.content .row .col1 {
30%;
}
.content .row .col2 {
15%;
}
.content .row .col3 {
20%;
}
.content .row .col4 {
20%;
}
.content .row .col3 {
15%;
}
.content .info {
overflow: hidden;
font-size: 16px;
line-height: 32px;
}
.content .info h3 {
float: left;
}
.content .info p {
float: right;
}
.content .row_btn {
position: absolute;
21px;
height: 10px;
background-color: red;
right: 10px;
top: 50%;
margin-top: -5px;
background: url(images/banner-icon.png) -28px -146px;
cursor: pointer;
}
.content .row_btn.up {
background-position: -2px -145px;
}
.content .detail {
display: none;
border-bottom: 1px solid #ccc;
}
.content .pageNav {
margin-top: 10px;
259px;
margin: 20px auto;
}
.content .pageNav ul {
list-style: none;
overflow: hidden;
}
.content .pageNav ul li {
float: left;
30px;
height: 30px;
line-height: 30px;
text-align: center;
margin-right: 5px;
cursor: pointer;
border: 1px solid #ccc;
}
.content .pageNav ul li.cur {
background-color: yellowgreen;
}
.mask {
position: absolute;
top: 0;
left: 0;
100%;
height: 100%;
background: url(images/busy.gif) no-repeat center center;
z-index: 999;
display: none;
}
</style>
</head>
<body>
<div class="content">
<div class="info">
<h3>职位信息</h3>
<p>一共有444个职位</p>
</div>
<div class="jobtable" id="jobtable">
<div class="mask"></div>
<div class="row hd">
<div class="cols">
<div class="col col1">职位名称</div>
<div class="col col2">职位类别</div>
<div class="col col3">工作地点</div>
<div class="col col4">招聘人数</div>
<div class="col col5">更新时间</div>
</div>
</div>
</div>
<div class="pageNav">
<ul>
<li class="cur"></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</div>
<script type="text/template" id="row_template">
<div class="row">
<div class="cols">
<div class="col col1">
<a href='<%=link%>'>
<%=name%>
</a>
</div>
<div class="col col2">
<%=postType%>
</div>
<div class="col col3">
<%=workPlace%>
</div>
<div class="col col4">
<%=recruitNum%>
</div>
<div class="col col5">
<%=publishDate%>
</div>
<div class="row_btn"></div>
</div>
<div class="detail">
<div className="serviceCondition">
<h5>入职资格: </h5>
<%=serviceCondition%>
</div>
<div className="workContent">
<h5>工作内容: </h5>
<%=workContent%>
</div>
</div>
</div>
</script>
<script type="text/javascript" src="js/jquery-1.12.3.min.js"></script>
<script type="text/javascript" src="js/underscore.js"></script>
<script>
// 生成数据绑定函数
var templateDataFun = _.template($("#row_template").html());
// 设置截流开关
var lock = true;
// 封装tabRow类
function RowCell(dictionary) {
this.dictionary = dictionary;
// 修正数据对象
this.dictionary.link = "http://talent.baidu.com/external/baidu/index.html#/jobDetail/2/" + this.dictionary.postId;
// 绑定DOM元素
this.$rowDom = $(templateDataFun(dictionary));
this.$btn = this.$rowDom.find(".row_btn");
this.$detail = this.$rowDom.find(".detail");
// 详情页开关状态
this.state = 0;
this.bindEvent();
this.render();
// 将每个实例存放入rowList管理
rowList.addRow(this);
}
// 渲染方法
RowCell.prototype.render = function() {
rowList.$dom.append(this.$rowDom)
};
// 给按钮绑定事件
RowCell.prototype.bindEvent = function() {
var self = this;
// 点击事件
this.$btn.click(function() {
if (self.state == 0) {
self.$btn.addClass("up");
self.$detail.stop(true).slideDown();
self.state = 1;
} else {
self.$btn.removeClass("up");
self.$detail.stop(true).slideUp();
self.state = 0;
}
})
};
// 清理DOM
RowCell.prototype.kill = function() {
this.$rowDom.remove();
};
// 封装rowTable类作为中介者
function RowTable() {
this.$dom = $("#jobtable")
this.rowArr = [];
this.navPage = new NavPage();
// 获取当前页面hash值
if (window.location.hash == "") {
window.location.hash = 1;
}
var pageNum = window.location.hash.substring(1);
this.getPage(pageNum);
};
// 向服务器发起数据请求
RowTable.prototype.getPage = function(num) {
lock = false;
var self = this;
$.get("JSON/getPostList" + num, function(data) {
data = JSON.parse(data);
self.navPage.upDate(num, data.totalPage);
// 先清理
_.each(self.rowArr, function(v) {
v.kill();
})
// 后渲染
_.each(data.postList, function(v, i) {
new RowCell(v)
});
lock = true;
})
};
// 添加实例到数组
RowTable.prototype.addRow = function(obj) {
this.rowArr.push(obj);
}
// 分页导航类
function NavPage(currentPage, totalPage) {
this.currentPage = currentPage;
this.totalPage = totalPage;
this.$pageList = $(".pageNav li");
this.render();
this.bindEvent();
}
// 分页导航渲染
NavPage.prototype.render = function() {
if (this.currentPage < 4) {
this.$pageList.eq(0).html(1);
this.$pageList.eq(1).html(2);
this.$pageList.eq(2).html(3);
this.$pageList.eq(3).html(4);
this.$pageList.eq(4).html("...");
this.$pageList.eq(5).html(this.totalPage - 1);
this.$pageList.eq(6).html(this.totalPage);
this.$pageList.eq(this.currentPage - 1).addClass("cur").siblings().removeClass("cur");
} else if (this.currentPage > this.totalPage - 3) {
this.$pageList.eq(0).html(1);
this.$pageList.eq(1).html(2);
this.$pageList.eq(2).html("...");
this.$pageList.eq(3).html(this.totalPage - 3);
this.$pageList.eq(4).html(this.totalPage - 2);
this.$pageList.eq(5).html(this.totalPage - 1);
this.$pageList.eq(6).html(this.totalPage);
this.$pageList.eq(this.currentPage - this.totalPage - 1).addClass("cur").siblings().removeClass("cur");
} else {
this.$pageList.eq(0).html(1);
this.$pageList.eq(1).html("...");
this.$pageList.eq(2).html(this.currentPage - 1);
this.$pageList.eq(3).html(this.currentPage);
this.$pageList.eq(4).html(this.currentPage + 1);
this.$pageList.eq(5).html("...");
this.$pageList.eq(6).html(this.totalPage);
this.$pageList.eq(3).addClass("cur").siblings().removeClass("cur");
}
}
// 分页导航更新
NavPage.prototype.upDate = function(currentPage, totalPage) {
this.currentPage = currentPage;
this.totalPage = totalPage;
this.render();
}
// 分页导航事件绑定
NavPage.prototype.bindEvent = function() {
var self = this;
this.$pageList.click(function() {
if (!lock) return;
if ($(this).html() == "...") return;
window.location.hash = $(this).html();
self.currentPage = parseInt($(this).html());
self.render();
rowList.getPage(self.currentPage);
})
}
var rowList = new RowTable();
</script>
</body>
</html>