最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • DOM事件与事件委托(未完结)

    正文概述 掘金(小孟不做白日梦)   2020-12-21   493

    今天我学习了DOM事件和事件委托,下面是我的笔记。

    DOM事件

    事件捕获

    定义:从外向内找监听函数

    事件冒泡

    定义:从内向外找监听函数

    addEventListener//事件绑定API

    W3C:baba.addEventListener('click',fn,bool)

    • 如果bool不传或者值为falsy→fn走冒泡(当浏览器在冒泡阶段发现baba有监听函数,就会调用fn,并提供事件信息)
    • 如果bool为true→fn走捕获(当浏览器在不活阶段发现baba有fn监听函数,就会调用fn,并提供事件信息)
    • 所以你可以选择改变bool的值来决定让fn先走冒泡还是先走捕获

    那么如果一个DOM元素中,既有冒泡,又有捕获,会先执行冒泡还是捕获呢?

    W3C规定,发生在w3c事件模型中的事件,先进入捕获阶段,达到目标元素(DOM元素绑定的事件被触发时,此时该元素为目标元素)之后,再进入冒泡阶段(所有事件的顺序是:其他元素捕获阶段事件→本元素代码顺序事件→其他元素冒泡阶段事件),这个可以这样理解:

    one.addEventListener('click',function(){
    console.log('one');
    },true);//捕获
    two.addEventListener('click',function(){
    console.log('two');
    },false);//冒泡
    three.addEventListener('click',function(){
    console.log('three');
    },true);//捕获
    four.addEventListener('click',function(){
    console.log('four');
    },false);//冒泡
    

    此时当我们点击four元素,four为目标元素,one作为根元素祖先(无论目标元素是捕获还是冒泡,在W3C下都是先从根元素执行捕获到目标元素,再从目标元素向上执行。),因此从one元素开始执行,
    one为捕获事件,执行;two为冒泡事件,忽略;three为冒泡事件,执行;four为冒泡事件,忽略;
    再从目标元素向上执行,则为four→two,执行结果为"one"、"three"、"four"、"two"

    当我们点击three元素,同理three元素变成了目标元素,one依然作为根元素,此时的执行结果为"one"、"three"、"two"

    target和currentTarget区别

    • e.target是用户点击
    • e.currentTarget是开发者监听
    • 监听代码中不建议使用this

    当有如下代码:

    <div>
      <span>
        {文字}
      </span>
    </div>
    

    当用户点击文字时,e.target就是span, e.currentTarget就是div

    • 但是当只有一个div被监听(不考虑父子同时被监听),fn分别在捕获阶段和冒泡阶段监听click事件,此时用户点击的就是开发者监听的,即谁先监听谁先执行。

    取消冒泡(捕获不可以取消,但是冒泡可以)

    • e.stopPropagation( ) 可以中断冒泡,一般用于封装某些独立的组件

    不可取消冒泡(有些特殊事件不可取消冒泡)

    • scroll event不可取消冒泡
    • 但是我们可以通过阻止wheel和touchsheet的默认动作来取消滚动,滚动条还能用的话可以通过css让滚动条的width:0

    事件委托

    定义:委托一个元素帮我监听我本该监听的事件

    监听祖先

    • 如果我们要给如下3个按钮添加点击事件:
    <div id="div1">
       <button>one</button>
       <button>two</button>
       <button>three</button>
    </div>
    

    我们可以监听这三个按钮的祖先:

    div1.addEventListener('click', (e)=>{
       const t = e.target
       if(t.tagName.toLowerCase() === "button"){
          console.log('clicked')
          console.log('button内容是'+t.textContent)
       }
    })
    

    此时当我们点击one这个按钮的时候,输出的结果是

    clicked
    button内容是one
    

    这样我们就通过监听祖先元素,给这三个按钮都加上了按钮点击事件

    • 如果我们要监听一个目前不存在元素的点击事件,同样是上面三个按钮,但是目前他们并不存在,他们将在一秒钟之后出现:
    setTimeout(()=>{
      const button = document.createElement('button')
      button.textContent = 'one'
      div1.appendChild(button)
    },1000)
    

    那么我们怎么用事件委托监听呢,同样的先监听祖先元素

    div1.addEventListener('click',()=>{
      const t = e.target
      if(t.tagName.toLowerCase() === 'button'){
        console.log('button clicked')
      }
    })
    

    此时我们点击one,结果是

    button clicked
    

    我们发现此时div1是动态判断的,不管之前有什么元素,我们只看点击这一刻的标签名是不是button

    • 综上我们发现事件委托的优点有:
    1. 省监听内存
    2. 可以监听动态元素

    封装事件委托

    接如上代码我们继续写到

    on('click','#div1','button',()=>{
      console.log('button clicked')
    })
    

    我们要如何实现只用on事件就可以做到在div1上面做事件委托,来看button有没有被点击呢?

    function on(eventType, element, selector, fn){ //接收四个参数
      if(!(element instanceof Element)){
        element = document.querySelector(element)
      }
      element.addEventListener(eventType,(e)=>{
        const t = e.target
        if(t.matches(selector)){ //matches判断一个元素是否匹配一个选择器
          fn(e)
        } 
      })
    }
    

    此时我们点击one,结果依然是

    button clicked
    
    但是注意:
    • 如果当前元素不匹配button,我们就要看父元素是否匹配,只要祖先元素中的某一项是button,就代表我此时点击的是button,代码如下
    function(eventType, element, selector, fn) {
        if(!(element instanceof Element)){
          element = document.querySelector(element)
        }
        element.addEventListener(eventType, e => {
          let el = e.target
          while (!el.matches(selector)) {
            if (element === el) { //当元素到达目标元素div1时
              el = null 
              break
            }
            el = el.parentNode //不匹配button时,看父元素是否匹配
          }
          el && fn.call(el, e, el)
        })
        return element
    }
    

    这种办法叫做递归判断

    那么JS支持事件吗?

    不支持。以上所写均为DOM事件,DOM事件和JS都是是浏览器的功能,他们是两个平行的功能,并没有从属关系。
    JS知识调用了DOM提供的addEventListener这个API而已

    • 那么我们要如何写出一个JS事件系统呢?

    这个问题留给以后的我


    起源地下载网 » DOM事件与事件委托(未完结)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元