1: ajax 是什么?有什么作用?
Ajax是Asynchronous JavaScript and XML的縮寫,這一技術(shù)能夠向服務(wù)器請(qǐng)求額外的數(shù)據(jù)而無需卸載整個(gè)頁面.
AJAX 在
瀏覽器與 Web 服務(wù)器之間使用異步數(shù)據(jù)傳輸(HTTP 請(qǐng)求)從服務(wù)器獲取數(shù)據(jù),這里的異步是指脫離當(dāng)前瀏覽器頁面的請(qǐng)求、加載等單獨(dú)執(zhí)行,這意味著可以在不重新加載整個(gè)網(wǎng)頁的情況下,通過JavaScript接受服務(wù)器傳來的數(shù)據(jù),然后操作DOM將新數(shù)據(jù)對(duì)網(wǎng)頁的某部分進(jìn)行更新,Ajax是一種瀏覽器和服務(wù)器的
通訊技術(shù),Ajax不是瀏覽器自帶功能open()方法的第三個(gè)參數(shù)表示請(qǐng)求采用異步還是同步方式,
默認(rèn)值為true–異步方式作用
使用Ajax最直觀的感受是向服務(wù)器獲取新數(shù)據(jù)不需要刷新頁面等待了,良好的用戶體驗(yàn)
2: 前后端開發(fā)聯(lián)調(diào)需要注意哪些事情?后端接口完成前如何 mock 數(shù)據(jù)?
- 注意點(diǎn):
-
約定數(shù)據(jù):需要傳輸?shù)臄?shù)據(jù)以及數(shù)據(jù)類型; -
約定接口:接口名稱,請(qǐng)求和響應(yīng)的格式,請(qǐng)求的參數(shù)名稱,響應(yīng)的數(shù)據(jù)格式; -
約定方式:是get還是post,后端用同樣的方式接收發(fā)送過來的數(shù)據(jù) - 前后端獨(dú)立開發(fā),前端向Mock Server發(fā)送請(qǐng)求,獲取模擬的數(shù)據(jù)進(jìn)行
開發(fā)和測(cè)試 - 如果接口修改了,Mock Server要
同步修改
-
如何 mock ?
方法一:本地Mock Server做法:前端把Mock Server克隆到本地,開發(fā)的時(shí)候,開啟前端工程服務(wù)器和Mock Server,所有的請(qǐng)求都發(fā)向本地服務(wù)器,獲取到Mock數(shù)據(jù).
方法二: 使用nodejs的express框架
3:點(diǎn)擊按鈕,使用 ajax 獲取數(shù)據(jù),如何在數(shù)據(jù)到來之前防止重復(fù)點(diǎn)擊?
- 1.在請(qǐng)求數(shù)據(jù)方法前引入布爾變量如
var isDataArrive = true,
2.在綁定按鈕點(diǎn)擊請(qǐng)求數(shù)據(jù)事件的方法里的開頭做次判斷,如果發(fā)請(qǐng)求前有值(即isDataArrive = ture),就return,不請(qǐng)求,因?yàn)樵?br> 3.在xhr.onreadystatechange方法里的判斷xhr.readystate的值===4的方法里引入布爾變量isDataArrive = true,
4.在發(fā)送請(qǐng)求的方法xhr.send()后引入布爾變量isDataArrive = false.
var check = true;
btn.addEventListener("click",function(){
if(!check){
return;
}
var xhr=new XMLHttpRequest()
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&(xhr.status==200||xhr.status==304)){
console.log(xhr.response);
check = true;
}
}
xhr.open(method,url,true);
xhr.send();
check=false
})
4:封裝一個(gè) ajax 函數(shù),能通過如下方式調(diào)用。后端在本地使用server-mock來 mock 數(shù)據(jù)
<script>
//封裝的方法
function ajax(opts){
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status === 200 || xhr.status === 304){
var results = JSON.parse(xhr.responseText)
opts.success('results')
}else{
opts.error()
}
}
}
var query = '?'
for (key in opts.data){
query += key + '=' + opts.data[key] + '&'
//query = query + key + '=' + opts.data[key] + '&'
//?username=xiaoming& 遍歷第一次
//?username=xiaoming&password=abcd1234& 第二次
}
query = query.substr(0, query.length-1)//去除最后一位的&--->?username=xiaoming&password=abcd1234
xhr.open(opts.type, opts.url+query, true)//配置參數(shù),這里 opts.url+query = '/login?username=xiaoming&password=abcd1234'
xhr.send()//發(fā)生請(qǐng)求
}
//點(diǎn)擊事件
document.querySelector('#btn').addEventListener('click', function () {
ajax({
url: '/login',//接口地址
type: 'get', // 類型, post 或者 get,
data: {
username: 'xiaoming',
password: 'abcd1234'
},
success: function (ret) {
console.log(ret); //ret為xhr.responseText,成功請(qǐng)求到的內(nèi)容
},
error: function () {
console.log('出錯(cuò)了')
}
})
});
</script>
5:實(shí)現(xiàn)加載更多的功能,效果范例,后端在本地使用server-mock來模擬數(shù)據(jù)
- 效果

使用Ajax加載更多
HTML__CSS部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>
加載更多
</title>
<style>
ul,
li {
margin: 0;
padding: 0
}
#ct li {
list-style: none;
border: 1px solid #ccc;
padding: 10px;
margin-top: 10px;
cursor: pointer;
}
#load-more {
display: block;
margin: 10px auto;
text-align: center;
cursor: pointer;
}
.btn {
display: inline-block;
height: 40px;
line-height: 40px;
width: 80px;
border: 1px solid #E27272;
border-radius: 3px;
text-align: center;
text-decoration: none;
color: #E27272;
}
.btn:hover {
background: green;
color: #fff;
}
#ct>li:hover {
background-color: pink;
}
</style>
</head>
<body>
<ul id="ct">
</ul>
<a id="load-more" class="btn" href="#">
加載更多
</a>
</body>
</html>
js部分
<script>
var ct = document.querySelector('#ct')
var btn = document.querySelector('#load-more')
var curIndex = 0 //當(dāng)前要加載的數(shù)據(jù)的序號(hào)
var len = 5 // 每次加載多少個(gè)數(shù)據(jù)
var isLoading = false //狀態(tài)鎖,用于判斷是否在加載數(shù)據(jù)
//點(diǎn)擊事件
btn.addEventListener('click', function (e) {
e.preventDefault(); //防止點(diǎn)擊 a 鏈接頁面跳到頂部
if (isLoading) {
return //如果正在請(qǐng)求數(shù)據(jù),那這次點(diǎn)擊什么都不做
}
//執(zhí)行到這里說明 沒有正在發(fā)出的請(qǐng)求,那后面就可以發(fā)請(qǐng)求
ajax('/loadMore', {
idx: curIndex,
len: len
}, function (data) {
appendData(data)
isLoading = false //數(shù)據(jù)到來之后 解
curIndex = curIndex + len //修改序號(hào),下次要數(shù)據(jù)就從新序號(hào)開始要
console.log(curIndex)
})
isLoading = true //發(fā)請(qǐng)求之前做個(gè)標(biāo)記加鎖
})
//封裝的函數(shù)
function ajax(url, json, onSuccess, onError) {
var xhr = new XMLHttpRequest()
var arr = []
for (key in json) {
arr.push(key + '=' + json[key])
}
url += '?' + arr.join('&')
xhr.open('get', url)
xhr.send()
xhr.onload = function () {//若xhr請(qǐng)求成功,就會(huì)觸發(fā)xhr.onreadystatechange和xhr.onload兩個(gè)事件。 那么我們到底要將成功回調(diào)注冊(cè)在哪個(gè)事件中呢?我傾向于 xhr.onload事件,因?yàn)閤hr.onreadystatechange是每次xhr.readyState變化時(shí)都會(huì)觸發(fā),而不是xhr.readyState=4時(shí)才觸發(fā)
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
onSuccess(JSON.parse(this.response))//this = xhr對(duì)象 this.response 是 responseText
} else {
onError && onError()
}
}
}
//封裝函數(shù),data 為 JSON.parse(this.response)即響應(yīng)內(nèi)容
function appendData(data) {
for (var i = 0; i < data.length; i++) {
var child = document.createElement('li')
child.innerText = data[i]
ct.appendChild(child)
}
}
function onError() {
console.log('出錯(cuò)了')
}
</script>
后端部分:router.js
app.get('/loadMore', function (req, res) {
var curIdx = req.query.idx//通過query去拿,這里的idx對(duì)應(yīng)前端js發(fā)生請(qǐng)求的參數(shù)idx
var len = req.query.len
var data = []
for (var i = 0; i < len; i++) {
data.push('頭條' + (parseInt(curIdx) + i))
}
res.send(data);
});