題目1: ajax 是什么?有什么作用?
ajax
是一種技術(shù)方案柴我,但并不是一種新技術(shù)堪伍。它依賴的是現(xiàn)有的CSS/HTML/Javascript
锚烦,而其中最核心的依賴是瀏覽器提供的XMLHttpRequest
對象,是這個對象使得瀏覽器可以發(fā)出HTTP請求與接收HTTP響應(yīng)帝雇。
所以我用一句話來總結(jié)兩者的關(guān)系:我們使用XMLHttpRequest
對象來發(fā)送一個Ajax
請求涮俄。
AJAX是對Asynchronous Javascript +XML的簡寫,它的誕生使得向服務(wù)器請求額外的數(shù)據(jù)而不用刷新頁面尸闸。它的優(yōu)缺點如下:
優(yōu)點:
更新數(shù)據(jù)而不需要刷新頁面: 它能在不刷新整個頁面的前提下與服務(wù)器通信維護(hù)數(shù)據(jù)彻亲,由于ajax是按照需求請求數(shù)據(jù),避免發(fā)送那些沒有改變的數(shù)據(jù)吮廉。
異步通信: 它與服務(wù)器使用異步的方式通信苞尝,不會打斷用戶的操作(卡死頁面)。
前后端負(fù)載平衡: 可以將后端服務(wù)器的一些工作轉(zhuǎn)移給客戶端宦芦,利用客戶端限制的能力來處理宙址,減輕了服務(wù)器的負(fù)擔(dān)。
數(shù)據(jù)與呈現(xiàn)分離: 利于分工调卑,降低前后耦合抡砂。
缺點:
瀏覽器歷史記錄的遺失: 在使用AJAX對頁面進(jìn)行改變后,由于并沒有刷新頁面恬涧,沒有改變頁面的訪問歷史注益,當(dāng)用戶想要回到上一個狀態(tài)時,無法使用瀏覽器提供的后退溯捆。
AJAX的安全問題: AJAX的出現(xiàn)就像建立起了一直通服務(wù)器的另一條通道丑搔,容易遭受到一些攻擊。
題目2: 前后端開發(fā)聯(lián)調(diào)需要注意哪些事情提揍?后端接口完成前如何 mock 數(shù)據(jù)啤月?
前后端開發(fā)聯(lián)調(diào)的注意事項:
- 約定接口數(shù)據(jù):有哪些需要傳輸?shù)臄?shù)據(jù),數(shù)據(jù)的類型是什么碳锈?
- 約定接口名稱:確定好接口的名稱顽冶,接口傳輸?shù)膮?shù),響應(yīng)的數(shù)據(jù)是什么售碳?響應(yīng)數(shù)據(jù)的格式强重。
- 根據(jù)接口需求整理成文檔绞呈。
后端接口完成前如何 mock 數(shù)據(jù) ?
- 可以根據(jù)接口文檔间景,使用假數(shù)據(jù)來驗證我們制作的頁面響應(yīng)和接口是否正常佃声。
- 安裝 xampp 環(huán)境模擬數(shù)據(jù)接收響應(yīng)。
- 使用 server-mock 來 mock 數(shù)據(jù)倘要。
題目3:點擊按鈕圾亏,使用 ajax 獲取數(shù)據(jù),如何在數(shù)據(jù)到來之前防止重復(fù)點擊?
//用狀態(tài)鎖
var lock = true; //狀態(tài)鎖默認(rèn)打開
btn = addEventListener("click", function(){
if(!lock) return; //如果狀態(tài)鎖為false封拧,則點擊直接return
lock = false; // 把狀態(tài)鎖賦值為false
xhr = onreadystatechange = function (){
if ( xhr.readyState === 4) {
lock = true; // 數(shù)據(jù)來了之后再把狀態(tài)鎖賦值為 true 志鹃,就可以進(jìn)行下一次點擊請求數(shù)據(jù)
}
}
})
題目4:封裝一個 ajax 函數(shù),能通過如下方式調(diào)用泽西。后端在本地使用server-mock來 mock 數(shù)據(jù)
function ajax(opts){ // todo ...}
document.querySelector('#btn').addEventListener('click', function(){
ajax({ url: '/login', //接口地址
type: 'get', // 類型曹铃, post 或者 get,
data: { username: 'xiaoming', password: 'abcd1234' },
success: function(ret){
console.log(ret); // {status: 0}
},
error: function(){
console.log('出錯了')
}
})
});
// 封裝ajax函數(shù)
function ajax(opts){
opts.success = opts.success || function(){};
opts.error = opts.error || function(){};
opts.type = opts.type || 'get';
opts.dataType = opts.dataType || 'json';
opts.data = opts.data || {};
var dataStr ='';
for (var key in opts.data) {
dataStr += key + '=' + opts.data[key] + '&';
}
var dataStr = dataStr.substr(0, dataStr.length - 1);
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState === 4){
if(xmlhttp.status === 200 || xmlhttp.status === 304){
if(opts.dataType === 'text') {
opts.onSuccess(xmlhttp.responseText);
}
if(opts.dataType === 'json') {
var json = JSON.parse(xmlhttp.responseText);
opts.success(json);
}
} else {
opts.error();
}
}
};
if (opts.type.toLowerCase() === 'post') {
xmlhttp.open(opts.type, opts.url, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-from-urlencoded");
xmlhttp.send(dataStr);
}
if (opts.type.toLowerCase() === 'get') {
xmlhttp.open(opts.type, opts.url + "?" + dataStr, true);
xmlhttp.send();
}
}
題目5:實現(xiàn)加載更多的功能,效果范例133捧杉,后端在本地使用server-mock來模擬數(shù)據(jù))
代碼成功例子截圖:
html代碼:
<!doctype html>
<html>
<head>
<meta name="name" content="content" charset="utf-8">
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div id="content">
<ul id="newsList">
</ul>
<button id="load-more" class="btn">加載更多</button>
</div>
<script>
var newsList = document.querySelector("#newsList");
var btn = document.querySelector("#load-more");
var pageIndex = 0;
var lock = false;
btn.addEventListener('click', function(){
if(lock) return;
lock = true;
loadData(function(news){
renderPage(news);
lock = false;
pageIndex += 5;
})
// 加載數(shù)據(jù)
function loadData(callback){
ajax({
type: 'get',
url: '/loadMore',
data: {
index: pageIndex,
length: 5
},
onSuccess: callback,
onError: function(){
console.log('出錯了');
}
});
}
// 創(chuàng)建代碼節(jié)點
function renderPage(news){
var fragment = document.createDocumentFragment();
for(var i=0; i<news.length; i++){
node = document.createElement('li');
node.innerText = news[i];
fragment.appendChild(node);
}
newsList.appendChild(fragment);
}
// 封裝 ajax 函數(shù)
function ajax(opts){
opts.onSuccess = opts.onSuccess || function(){};
opts.onError = opts.onError || function(){};
opts.type = opts.type || 'get';
opts.dataType = opts.dataType || 'json';
opts.data = opts.data || {};
var dataStr ='';
for (var key in opts.data) {
dataStr += key + '=' + opts.data[key] + '&';
}
var dataStr = dataStr.substr(0, dataStr.length - 1);
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState === 4){
if(xmlhttp.status === 200 || xmlhttp.status === 304){
if(opts.dataType === 'text') {
opts.onSuccess(xmlhttp.responseText);
}
if(opts.dataType === 'json') {
var json = JSON.parse(xmlhttp.responseText);
opts.onSuccess(json);
}
} else {
opts.onError();
}
}
};
if (opts.type.toLowerCase() === 'post') {
xmlhttp.open(opts.type, opts.url, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-from-urlencoded");
xmlhttp.send(dataStr);
}
if (opts.type.toLowerCase() === 'get') {
xmlhttp.open(opts.type, opts.url + "?" + dataStr, true);
xmlhttp.send();
}
}
})
</script>
</body>
</html>
router.js部分:
app.get('/loadMore', function(req, res){
var curIdx = req.query.index;
var len = req.query.length;
var data = [];
for(var i=0; i<len; i++){
data.push('新聞' + (parseInt(curIdx) + i));
}
res.send(data);
});
css部分:
ul,
li {
padding: 0;
margin: 0;
}
li {
list-style: none;
}
#content {
width: 600px;
margin: 0 auto;
}
#newsList > li{
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
}
#newsList > li:hover {
background-color: #87B7FF;
color: #fff;
}
.btn {
width: 100px;
height: 50px;
display: block;
margin: 10px auto;
color: #fff;
border: none;
border-radius: 15px;
box-shadow: 0 8px #ccc;
background: #4CAF50;
text-align: center;
text-decoration: none;
outline: none;
cursor: pointer;
-webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s;
}
.btn:hover {
background-color: #008CBA; /* Green */
color: white;
}
.btn:active {
background-color: #3e8e41;
box-shadow: 0 5px #666;
transform: translateY(4px);
}