题目1: ajax 是什么?有什么作用?
ajax
是一种技术方案,但并不是一种新技术。它依赖的是现有的CSS/HTML/Javascript
,而其中最核心的依赖是浏览器提供的XMLHttpRequest
对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。
所以我用一句话来总结两者的关系:我们使用XMLHttpRequest
对象来发送一个Ajax
请求。
AJAX是对Asynchronous Javascript +XML的简写,它的诞生使得向服务器请求额外的数据而不用刷新页面。它的优缺点如下:
优点:
更新数据而不需要刷新页面: 它能在不刷新整个页面的前提下与服务器通信维护数据,由于ajax是按照需求请求数据,避免发送那些没有改变的数据。
异步通信: 它与服务器使用异步的方式通信,不会打断用户的操作(卡死页面)。
前后端负载平衡: 可以将后端服务器的一些工作转移给客户端,利用客户端限制的能力来处理,减轻了服务器的负担。
数据与呈现分离: 利于分工,降低前后耦合。
缺点:
浏览器历史记录的遗失: 在使用AJAX对页面进行改变后,由于并没有刷新页面,没有改变页面的访问历史,当用户想要回到上一个状态时,无法使用浏览器提供的后退。
AJAX的安全问题: AJAX的出现就像建立起了一直通服务器的另一条通道,容易遭受到一些攻击。
题目2: 前后端开发联调需要注意哪些事情?后端接口完成前如何 mock 数据?
前后端开发联调的注意事项:
- 约定接口数据:有哪些需要传输的数据,数据的类型是什么?
- 约定接口名称:确定好接口的名称,接口传输的参数,响应的数据是什么?响应数据的格式。
- 根据接口需求整理成文档。
后端接口完成前如何 mock 数据 ?
- 可以根据接口文档,使用假数据来验证我们制作的页面响应和接口是否正常。
- 安装 xampp 环境模拟数据接收响应。
- 使用 server-mock 来 mock 数据。
题目3:点击按钮,使用 ajax 获取数据,如何在数据到来之前防止重复点击?
//用状态锁
var lock = true; //状态锁默认打开
btn = addEventListener("click", function(){
if(!lock) return; //如果状态锁为false,则点击直接return
lock = false; // 把状态锁赋值为false
xhr = onreadystatechange = function (){
if ( xhr.readyState === 4) {
lock = true; // 数据来了之后再把状态锁赋值为 true ,就可以进行下一次点击请求数据
}
}
})
题目4:封装一个 ajax 函数,能通过如下方式调用。后端在本地使用server-mock来 mock 数据
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函数
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:实现加载更多的功能,效果范例133,后端在本地使用server-mock来模拟数据)
代码成功例子截图:
Paste_Image.png
Paste_Image.png
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;
})
// 加载数据
function loadData(callback){
ajax({
type: 'get',
url: '/loadMore',
data: {
index: pageIndex,
length: 5
},
onSuccess: callback,
onError: function(){
console.log('出错了');
}
});
}
// 创建代码节点
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 函数
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);
}