问答
一、ajax 是什么?有什么作用?
Ajax是Asynchronous JavaScript and XML的缩写,通过new XMLHttpRequest创建对象,它是一个具有应用程序接口的JavaScript对象,能够使用超文本传输协议连接1个服务器,是微软在1999年IE5.0浏览器中率先提出的。通过这个对象向服务器请求额外的数据,去获取数据,而无需卸载整个页面,带来良好的用户体验。
二、前后端开发联调需要注意哪些事情?后端接口完成前如何 mock 数据?(npm install -g server-mock)
- 前后端联调
前后端联调是一种真实业务数据和本地mock数据之间来回切换,以达到前后端分离架构下的不同开发速度时数据交换的一种方式方法。需要注意的有: - 数据:需要约定好传输的数据以及类型。
- 接口:确定接口名称及请求和响应的格式,请求的参数名称、响应的数据格式。
- 后端接口完成前mock 数据
- 可以搭建php本地服务器,php写脚本提供临时数据;
- 也可使用Mock.js,它能拦截ajax请求并根据请求中的内容来随机生成符合你要求的假数据,模拟后端环境让你完成对页面和接口的测试。
- 也可以安装server-mock这样的工具,这样不需要特地去写一个后台的处理页面文件来访问数据。
三、点击按钮,使用 ajax 获取数据,如何在数据到来之前防止重复点击?
- setTimeout + clearTimeout
连续的点击会把上一次点击清除掉,也就是ajax请求会在最后一次点击后发出去。 - disable 按钮。
- 给一个flag状态,用户点击后变为false,在数据到来之前不再发送请求,ajax成功后设为true。
代码
一、封装一个 ajax 函数,能通过如下方式调用。
function ajax(opts){
// todo ...
}
document.querySelector('#btn').addEventListener('click', function(){
ajax({
url: 'getData.php', //接口地址
type: 'get', // 类型, post 或者 get,
data: {
username: 'xiaoming',
password: 'abcd1234'
},
success: function(ret){
console.log(ret); // {status: 0}
},
error: function(){
console.log('出错了')
}
})
});
function ajax(opts){
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if(req.readyState == 4 && req.status == 200)
{
console.log(req.responseText)
var json = JSON.parse(req.responseText);
opts.success(json);
}
if(req.readyState == 4 && req.status == 404)
{
opts.error();
}
}; //事件监听函数
var dataStr = '';
for(var key in opts.data)
{
dataStr += key + '=' + opts.data[key] + '&';
}
dataStr = dataStr.substr(0, dataStr.length-1); // var re = /&$/g
if (opts.type.toLowerCase() === 'post')
{
req.open(opts.type, opts.url, true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.send(dataStr);
}
if(opts.type.toLowerCase() === 'get')
{
req.open(opts.type, opts.url + '?' + dataStr, true);
req.send();
}
}
document.querySelector('#btn').addEventListener('click', function(){
ajax({
url: 'getData.php', //接口地址
type: 'get', // 类型, post 或者 get,
data: {
username: 'xiaoming',
password: 'abcd1234'
},
success: function(ret){
console.log(ret); // {status: 0}
},
error: function(){
console.log('出错了')
}
})
});
二、实现如下加载更多的功能。
效果如下: 加载更多
使用server mock工具实现。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>加载更多</title>
</head>
<style>
*{
margin: 0;
padding: 0;
}
li{
list-style: none;
margin: 8px;
padding: 4px;
border: 1px solid #ccc;
font-size: 25px;
line-height: 50px;
cursor: pointer;
}
li:hover{
background: green;
}
.btn{
cursor: pointer;
padding: 5px;
margin: 30px 0;
font-size: 25px;
line-height: 50px;
color: purple;
border: 1px solid red;
background: #fff;
outline:none;
}
p{
text-align: center; // 按钮居中
}
</style>
<body>
<ul class="wrap">
<li>内容1</li>
<li>内容2</li>
</ul>
<p><button class="btn">加载更多</button></p>
<script type="text/javascript">
var wrap = document.querySelector('.wrap');
var btn = document.querySelector('.btn');
var current = 3;
var isLoading = false;
btn.addEventListener('click', function() {
if(isLoading)
{
return;
}
isLoading: true;
btn.innerText = '正在加载,请稍后...';
ajax({
url: '/getMore',
data: {
start: current,
len: 6
},
success: function(data) {
isLoading = false;
btn.innerText = '加载更多';
if(data.status == 0)
{
getMore(data);
current += 6;
}else{
alert('出错啦')
}
},
error: function() {
onError();
}
});
});
function ajax(opts) {
var req = new XMLHttpRequest();
req.onreadystatechange = function () {
if (req.readyState == 4 && req.status == 200)
{
var result = JSON.parse(req.responseText);
opts.success(result);
}
if (req.readyState == 4 && req.status == 404)
{
opts.error();
}
};
var filter = '';
for(var key in opts.data)
{
filter += key + '=' + opts.data[key] + '&';
}
filter = filter.substr(0, filter.length-1);
req.open('get', opts.url + '?' + filter, true);
req.send();
};
function getMore(data) {
var data = data.data;
for (var i=0; i<data.length; i++)
{
var li = document.createElement('li');
li.innerText = '内容' + data[i];
wrap.appendChild(li);
}
}
function onError() {
isLoading: false;
btn.innerText = '加载更多';
alert('系统异常');
}
</script>
</body>
</html>
router.js
app.get('/getMore', function(req, res) {
// var start = req.query.start,
// len = req.query.len;
var data = [];
for(var i=0; i<req.query.len; i++)
{
data.push(req.query.start++);
}
res.send({
status: 0,
data: data,
})
})
请求接收的数据
加载更多
三、实现注册表单验证功能
效果如下:表单注册
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册验证</title>
<style>
form{
font-size: 20px;
}
fieldset label {
float:left;
width:120px;
text-align:right;
padding:4px;
margin:1px;
}
fieldset div {
clear:left;
margin:20px 0;
}
input{
height: 35px;
}
.help{
color: #bbb;
}
.submit{
margin-left: 205px;
}
.borderRed{
border: 1px solid red;
}
</style>
</head>
<body>
<h1>注册</h1>
<form id="register" action="" method="post" >
<fieldset>
<div>
<label>用户名:</label>
<input class="username" type="text" name="username" placeholder="用户名(hunger被注册过)">
<span class="help usernameWarning">只能是字母、数字、下划线,3-10个字符</span>
</div>
<div>
<label>密码:</label>
<input class="password" type="password" name="pwd">
<span class="help pwdWarning">大写字母、小写、数字、下划线最少两种,6-15个字符</span>
</div>
<div>
<label>再输一次:</label>
<input class="passwordAgain" type="password" name="pwdAgain" placeholder="再输入一次密码">
<span class="help pwdAgainWarning"></span>
</div>
<input class="submit" type="submit" value="注册"><br/>
</fieldset>
</form>
<script>
var register = document.querySelector('#register');
var password = null;
var submit = document.querySelector('.submit');
var warning = {
userExist: "用户名已经存在",
usernameformatError: "输入的用户名格式不正确,请重新填写!",
usernameAvailable: "用户名可用",
passwordFormatError: "输入的密码格式不正确,请重新设置!",
passwordAvailable: "密码可用",
passwordDifferent: "两次输入的密码不一致!",
};
register.addEventListener('focusout', function(e){
// var className = e.target.className;
var value = e.target.value;
var name = e.target.name;
var className = e.target.className;
switch(name){
case 'username':
checkUser(e, value, className);
break;
case 'pwd':
checkPassword(e, value, className);
break;
case 'pwdAgain':
checkPasswordAgain(e, value, className, password);
break;
}
})
submit.addEventListener('click', function(e){
e.preventDefault();
console.log(document.getElementsByClassName('borderRed'));
if(document.getElementsByClassName('borderRed').length == 0)
{
enroll();
}
})
// 验证用户名是否输入合法
function checkUser(e, value, className) {
console.log(e);
var reg = /^\w{3,10}$/g;
if(value == "hunger")
{
document.querySelector('.usernameWarning').innerText = warning.userExist;
e.target.className = addClass(className, 'borderRed');
return false;
}
if(!reg.test(value))
{
document.querySelector('.usernameWarning').innerText = warning.usernameformatError;
console.log(document.querySelector('.usernameWarning'));
console.log(document.getElementsByClassName('username')[0]);
e.target.className = addClass(className, 'borderRed');
console.log(className);
return false;
}
if(hasClass(className, 'borderRed'))
{
e.target.className = removeClass(className, 'borderRed');
}
document.querySelector('.usernameWarning').innerText = warning.usernameAvailable;
return true;
}
// 验证密码是否合法 (/\w{,6}|\w{20,}/g).test(value)
function checkPassword(e, value, className) {
password = value;
if((value.length < 6) || (value.length > 15) || ((/[^\w]/g).test(value)) || ((/^[a-z]+$|^[A-Z]+$|^[0-9]+$|^[_]+$/).test(value)))
{
document.querySelector('.pwdWarning').innerText = warning.passwordFormatError;
e.target.className = addClass(className, 'borderRed');
return false;
}
if(hasClass(className, 'borderRed'))
{
e.target.className = removeClass(className, 'borderRed');
}
document.querySelector('.pwdWarning').innerText = warning.passwordAvailable;
return true;
}
// 两次密码是否输入一致
function checkPasswordAgain(e, value, className, password) {
if(value != password)
{
console.log(document.querySelector('.passwordAgain'));
document.querySelector('.pwdAgainWarning').innerText = warning.passwordDifferent;
e.target.className = addClass(className, 'borderRed');
return false;
}
if(hasClass(className, 'borderRed'))
{
e.target.className = removeClass(className, 'borderRed');
}
document.querySelector('.pwdAgainWarning').innerText = '';
return true;
}
// 发送数据
function enroll() {
ajax({
url: '/register',
type: 'post',
data: {
username: document.querySelector('.username').value,
password: document.querySelector('.password').value,
},
success: function(list) {
alert(list.msg);
},
error: function() {
alert("出错啦");
}
})
}
function ajax(opts) {
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if(req.readyState == 4 && req.status == 200)
{
var json = JSON.parse(req.responseText);
opts.success(json);
}
if(req.readyState == 4 && req.status == 404)
{
opts.error();
}
}
var dataStr = '';
for (var key in opts.data)
{
dataStr += key + '=' + opts.data[key] + '&';
}
dataStr = dataStr.substr(0, dataStr.length-1);
req.open(opts.type, opts.url, true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.send(dataStr);
}
function hasClass(className, cls) {
var reg = new RegExp('(\\s|^)' + cls + '(\\b|$)', 'g');
return reg.test(className)
}
function addClass(className, cls) {
if (!hasClass(className, cls)) {
return className += ' ' + cls;
}
return className; // 不要忘记return
}
function removeClass(className, cls) {
if (hasClass(className, cls)) {
var reg = new RegExp('(\\s|^)' + cls + '(\\b|$)', 'g');
return className = className.replace(reg, '').replace(/\s{2,}/g, ' ');
}
return className; // 不要忘记return
}
</script>
</body>
</html>
router.js
// 注册
app.post('/register', function(req, res) {
// var start = req.query.start,
// len = req.query.len;
res.send({
status: 0,
msg: "恭喜你,注册成功!",
})
})
请求接受的数据
注册
网友评论