需求:在向服务器发送请求,获取数据后,动态创建一个盒子,然后点击盒子时,修改盒子的样式。
// 核心代码(有问题版本)
$.ajax({
url:'...',
method:'get',
success(result){
$('body').append('<div>...</div>'); // 创建盒子
}
});
$('#box').click(function(){
$(this).css('background','lightcoral');
})
这样写你会发现,点击盒子并不会修改它的样式。原因在于AJAX请求是异步的,而执行$('#box').click(...)
这一行代码是同步的。
请求还没有成功返回,也就不会动态创建盒子,$('#box')
是空的,拿不到元素咋给它设置样式呢?
解决方案一:
把事件绑定的代码挪到success函数里面,就可以保证创建元素之后再改样式。
$.ajax({
url:'...',
method:'get',
success(result){
$('body').append('<div>...</div>'); // 创建盒子
$('#box').click(function(){
$(this).css('background','lightcoral');
})
}
});
解决方案二:通过事件委托机制进行绑定。
将点击事件绑定给body(一定存在),再通过判断事件源做相关处理。
let $body = $('body');
$body.click(function(ev){
let target = ev.target,
$target = $(target); // 把DOM对象转换为JQ对象
if(target.id === 'box'){
$(this).css('background','lightcoral');
}
})
// 但凡可以点击,盒子肯定已经创建完成了
AJAX的核心四步
let xhr = new XMLHttpRequest;
xhr.open('...','...',true);
xhr.onstatechange = function(){
...
}
xhr.send();
xhr.open
方法的第三个参数为是否为异步,默认为true异步,false为同步。这个同步异步怎么回事呢?
指的是从send()发送请求开始,到AJAX状态为4接收到响应为止:
同步:这期间只处理请求,其他所有任务都不处理。
异步:该干嘛干嘛,不等响应回来就干别的。它会把请求任务放在事件队列的宏任务中。
let xhr = new XMLHttpRequest;
xhr.open('...','...',true); // 异步
// open之后,xhr.readyState为1
xhr.onstatechange = function(){ // 监听到readyState值变化才会触发
console.log(xhr.readyState);
}
xhr.send();
// 依次输出2、3、4
let xhr = new XMLHttpRequest;
xhr.open('...','...',true); // 异步
xhr.send();
xhr.onstatechange = function(){
console.log(xhr.readyState);
}
// 仍然依次输出2、3、4,状态修改为2之前就已经绑定好了
let xhr = new XMLHttpRequest;
xhr.open('...','...',false); // 同步
xhr.send(); // 从这时候开始一直到状态为4,下面代码都不能执行。
// 变为4之后才继续,那时就不再变化了,所以永远不触发。
xhr.onstatechange = function(){
console.log(xhr.readyState);
}
// 不输出
let xhr = new XMLHttpRequest;
xhr.open('...','...',true); // 同步
// 这时候readyState为1
xhr.onstatechange = function(){
console.log(xhr.readyState);
}
xhr.send(); // 任务开始,直到状态为4,期间监听到了状态变化,但无能为力。
// 任务结束后,才触发onstatechange,状态从1->4
// 输出 4