问:JavaScript动画与CSS3动画有什么区别?
答:优先选择css设置动画,因为不需要进行js解析,不会改变已经渲染好的dom树,也就不会引起重绘或者回流,性能好,但是css对于动画的控制较弱,所以中间控制过程较多的复杂动画需要用js实现,或者CSS3出现兼容问题,选择js动画
问:DOM事件模型?如何阻止事件冒泡、默认行为?
答:
<1> DOM事件模型分为两种:事件捕获和事件冒泡
事件捕获模型里目标元素触发事件,事件会从根开始,依次传过目标元素的上级元素,传到目标元素,事件所经过的元素全部触发事件;
事件冒泡模型里目标元素触发事件,事件会从目标元素开始,依次传过目标元素的上级元素,直到根,事件所经过的元素全部触发事件;
<2>
2.1 阻止事件冒泡和事件的默认行为
自定义一个事件处理函数,返回false,取消事件,可以同时阻止事件冒泡与事件默认行为
2.2 阻止事件冒泡
方法1: W3C方法用e.stopPropagation(),IE浏览器不支持,IE用e.cancelBubble(),封装一个方法判断浏览器类型,选择对应的方法阻止冒泡
function bubbles(e){
let ev = e || window\.event
if(ev&\&ev.stopPropagation){
//非IE浏览器
ev.stopPropagation()
}else{
//IE浏览器(IE11以下)
ev.cancelBubble = true
}
}
方法2:e.stopImmediatePropagation(),阻止后续事件处理函数执行,不论是目标元素的事件监听,还是上级元素的事件监听
<div>
<a href="https://juejin.cn/" id="testA">a跳转</a>
</div>
<script>
document.querySelector('div').addEventListener('click',(e)=>{
//补充:e.target是触发事件的元素,e.currentTarget是绑定当前事件监听的对象
console.log('div事件委托处理',e.target,e.currentTarget)//输出失败
})
document.querySelector('#testA').addEventListener('click',(e)=>{
e.preventDefault() //阻止默认行为
e.stopImmediatePropagation() //阻止后续事件处理函数执行
//补充:e.stopPropagation()阻止冒泡
console.log('第1次事件处理',e.target,e.currentTarget)//成功输出
})
document.querySelector('#testA').addEventListener('click',(e)=>{
e.preventDefault()
console.log('第2次事件处理',e.target,e.currentTarget)//输出失败
})
</script>
2.3 阻止默认行为
W3C方法用e.preventDefault(),IE浏览器不支持,IE用e.returnValue=false,封装一个方法判断浏览器类型,选择对应的方法阻止默认行为
function defaultB(e){
if(e.preventDefault){
e.preventDefault()
}else{
//a的默认行为,不是click的默认行为,所以用window\.event,不用e
window\.event.returnValue=false
}
}
问:事件三要素?
答:
事件源:触发事件的对象
事件类型:动作,比如点击或者鼠标划过
事件处理函数:事件处理程序
记忆逻辑:事件就是发现用户在哪里(事件源)完成了什么动作(事件类型),规定网页如何处理这个动作(事件处理函数)
问:DOM和BOM的区别
答:BOM是浏览器对象模型,没有自己的通用标准(不一样的浏览器标准肯定不一样,但是主流浏览器大多数js代码大同小异),顶级对象是Window; DOM是文档对象模型,适用W3C标准,顶级对象是Window.document,简写为document
5.编写一个通用的事件监听函数?
//准备一个嵌套盒子
<div id="outer">
<a href="https://juejin.cn/" id="inner">a跳转</a>
</div>
//js
<script>
const a = document.querySelector('#outer')
//调用函数
bind(a,'click','#inner',(e)=>{
e.preventDefault()
console.log(e.target,e.currentTarget)
})
//定义函数
function bind (ele,type,selector,fn){
//判断是否事件委托,不是则事件源选择器字符串selector=undefined
if(fn==null){
fn=selector,
selector=undefined
}
ele.addEventListener(type,(e)=>{
//如果是事件委托,判断事件源与设置监听的事件对象是否相同
if(selector){
let target = e.target
if(target.matches(selector)){
//更改回调函数this并赋实参e
fn.call(target,e)
}else{
fn(e)
}}})}