常见基础问题(DOM)

159 阅读1分钟

简述DOM事件模型

先经历从上到下的捕获过程,再经历从下到上的冒泡过程。 可能会用到一个api,addEventListener('事件类型','函数','选项'),在第三个参数可以选false/true或者不填。false表示冒泡。true表示捕获。默认为false。

e.target和e.currentTarget

e.target是用户操作的元素。

e.currentTarget是被监听的元素。

事件委托

把事件监听放在祖先元素(如父元素、爷爷元素)上。

手写事件委托。

简易版

ul.addEventListener('click',function(e){
  if(e.target.tagName.toLowerCase()==='li'){
     fn()  //执行某个函数
     }
})

如果用户点击的是li里的span,就无法出发,是个bug。

高级版

function delegata(element,eventType,selector,fn){
    element.addEventListener(eventType,e=>{
      let el=e.target
      while (!el.matches(selector)){
        if (element === el){
          el ===null
          break
          }
          el = el.parentNode
        }
      el && fn.call(el,e,el)
      })
      return element
}

delegate(ul,'click','li',f1)

优点

  1. 节约监听数量
  2. 可以监听动态生成的元素

缺点

如果一个元素祖元素太多,难以找到监听者,调试复杂。

可拖拽的div

要注意监听document,避免移动过快导致超出div之后失去监听,而无法移动的情况。最好改成transform而不是top和left,增加性能。

div{
  border: 1px solid red;
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
}

*{margin:0; padding: 0;}

//html写一个<div id = "xxx"></div>
var dragging = false
var position = null

xxx.addEventListener('mousedown',function(e){
    dragging = true //正在移动
    position = [e.clientX,e.clientY]
})

document.addEventListener('mousemove',function(e){
    if (dragging === false){return} //没有移动
    const x = e.clientX 
    const y = e.clientY
    const changeX = x - position[0]
    const changeY = y - position[1]
    const left = parseInt(xxx.style.left || 0)
    const top = parseInt(xxx.style.top || 0)
    xxx.style.left = left + changeX + 'px'
    xxx.style.top = top + changeY + 'px'
    position = [x,y]
})

document.addEventListener('mouseup',function(e){
    dragging = false
})

示例代码