制作“点击别处关闭浮层”效果
- debugger
-
event.stopPropagation()
这个方法用于阻止事件的传播 - 用css制作一个小三角
#triangle{
border:10px solid transparent;
border-right:5px solid red;
}
-
在某元素上添加了 preventDefault() 会导致它本身和它的子元素里的checkbox(
)无法被点击(因为默认动作都被阻止了)
如何节省监听器内存?
在实际网页中我们只需要在浮层弹出时设定一个一次性事件监听器
$('button').on('click',function(x){
$(popover).show()
$(document).one('click',function(x){
$(popover).hide()
})
})
这样在浮层没有被弹出时,不对document进行监听,就很好的减少了内存的使用
- 如何解决下图一个小bug?(两种方法)
如果代码照下面写,会导致点击按钮后浮层不弹出的问题
$('button').on('click', function (x) {
$(popover).show()
console.log('展示浮层')
$(document).one('click', function (x) {
$(popover).hide()
console.log('隐藏浮层')
})
})
可以看到同时执行了两个函数,这是因为在‘click’事件的target阶段就已经将document的监听器设定好了,等到‘click’事件冒泡到document时一次性监听器中的函数就会被执行
方法1:给button的父级元素添加 event.stopPropagation()方法
//此时button的父级元素是wrapper
wrapper.addEventListener('click',function(x){
x.stopPropagation()
})
方法2:用setTimeout()
$('button').on('click', function (x) {
$(popover).show()
console.log('展示浮层')
setTimeout(function () {
$(document).one('click', function (x) {
$(popover).hide()
console.log('隐藏浮层')
})
}, 0)
})
-
setTimeout(()=>{},0)
是如何实现异步操作的 - 最终代码
$('#btn').on('click',function () {
$('#popover').toggleClass('show')
.one('click',()=>{
setTimeout(function () {
$(document).on('click',function () {
$('#popover').removeClass('show');
})
},0)
})
})
$('#wrap').on('click',function (e) {
e.stopPropagation();
})
DOM事件的进一步了解
http://js.jirengu.com/jamirapaqi/1/edit
无缝轮播
- 无缝轮播一个bug:从其他页面切换回无缝轮播页面的时候,会出现轮播乱了的情况(自己做做看),原因在于浏览器在页面切出去后不会执行
setInterval()
的内容,在等用户切回页面之后,再同时执行setInterval()
的内容,这导致了轮播可能出现混乱 - 解决方法1:通过监听
visibilitychange
事件,在用户没有看该页面时把setInterval()
停掉,代码如下:
document.addEventListener('visibilitychange', function (x) {
if (document.hidden) { ///如果当前页面没有被浏览就不要再执行轮播
window.clearInterval(timer)
} else {///如果切换回轮播页面,重新启动轮播效果
timer = setInterval(() => {
slide(n)
n++
}, 1500)
}
})
document.hidden
返回布尔值,用于查看当前页面是否被浏览
这可以防止轮播混乱
- 要实现又能点击切换图片又能无缝轮播
用到element属性:outerHTML
用到以下jQueryAPI
clone()
append()
末尾插入元素,可以接受DOM元素、jQ对象、字符串
prepend()
最前面插入元素,可以接受DOM元素、jQ对象、字符串 - 在一句代码中出现
hide()
和show()
,浏览器可能会同时处理,没办法达到想要的效果。此时在中间加入offset()
,会使浏览器不同时进行offset()
和show()
,达到想要的效果
.offset()
返回一个对象,该对象包含jQ对象相对于document
的位置
$(btn).eq(0).on('click',()=>{
if(current === 2){
$slide.css({'transform':'translateX(-1200px)'})
.one('transitionend',()=>{
$slide.hide().offset()
$slide.css({'transform':'translateX(-400px)'})//.offset()返回的不是jQ对象所以不能直接链式操作
})
}
})
猜想用setTimeout(fn,0)
也能实现相同效果,但发现在切换的动画过程中会有闪烁
$btn.eq(0).on('click',()=>{
if(current === 2){
$slide.css({'transform':'translateX(-1200px)'})
.one('transitionend',()=>{
$slide.hide()
setTimeout(() => {
$slide.css({'transform':'translateX(-300px)'}).show()
}, 0);
})
事件流
事件流描述的是事件在页面中传播的顺序,它包括三个阶段:捕获阶段、目标阶段、冒泡阶段。
在DOM2级事件中,用addEventListener()
来处理事件。该函数接受三个参数,由第三个参数决定事件被触发后回调函数在哪个阶段被执行,该参数默认为false,即冒泡阶段被执行。
需要注意的是,触发事件时嵌套最深,最底层的那个元素,它没有冒泡和捕获阶段,仅有目标阶段。而在目标阶段,回调函数的执行顺序只由代码的顺序决定。