Tracy JS 小笔记 - 事件

事件绑定

  • 交互体验的核心功能
  • dom.on### = function(){}
    • 这种绑定兼容性特别好
    • this 指向 dom 元素自己
    • 缺点:一个事件只能绑定一个函数,写两个的话 后一个会覆盖前一个
      mydiv.onclick = function(){console.log("a");}
      mydiv.onclick = function(){console.log("b");}
      只能输出 b, 因为它本质上还是属性赋值
    • 基本等同于写在元素行间上
      <div οnclick="console.log("b");">
  • dom.addEventListener(事件类型,处理函数,false) 事件监听机制
    • div.addEventListener('click', function(){}, false); //注意 这里是 click 不是 onclick
    • this 指向 dom 元素自己
    • IE9 以下不兼容
    • 可以给一个对象的一个事件绑定多个处理函数, 并且按照绑定的顺序来执行
      div.addEventListener('click', function(){console.log("a");}, false);
      div.addEventListener('click', function(){console.log("b");}, false);
      a, b 都能打印出来
    • div.addEventListener('click', test, false);
      div.addEventListener('click', test, false);
      var test = function(){console.log("a");}
      这个算绑定一次,只会打印出一个 a
    • 事件监听最后的参数变成 true, 就会立刻变成事件捕获模型, false 的时候是冒泡
    • dom.attachEvent('on' + 事件类型,处理函数)
      • dom.attachEvent('onclick', function(){});
      • IE 特有的方法,谷歌火狐啥的都不行
      • this 指向 window,这个其实相当于一个 IE 浏览器的一个 bug 了,我们肯定是想让 this 指向 dom 元素自己,我们就自己处理
        div.attachEvent('onclick', function(){test().call(div);}, false);
        var test = function(){console.log(this);}//这里的 this 就指向自己了
      • 和 addEventListener 差不多 但是div.attachEvent('onclick', test, false);
        div.attachEvent('onclick', test, false);
        var test = function(){console.log("a");}
        这个算绑定两次,只会打印出两个 a
  • 封装兼容性的事件绑定,兼容性最好的时间绑定
    Element.prototype.addEvent = function(type, handle){
        if(this.addEventListener){
            this.addEventListener(type, handle, false);
        }else if(this.attachEvent){
            this.attachEvent('on' + type, function(){
                handle.call(this); //处理 IE this 指向 window 的 bug
            });
        }else{
            this['on'+type] = handle;
        }
    }
    
    var div = document.getElementsByClassName("carousel")[0];
    div.addEvent("click", function() { console.log(this); });
                            
  • onclick 单击事件
    var mydiv = document.getElementsByTagName("div")[0];
    mydiv.onclick = function(){}
  • 键盘事件
    • onkeydown/onkeyup 用户按下/抬起键盘任意按键
      document.onkeydown = function(e){
      var event = e || window.event; //兼容 IE
      console.log(event); //这里查看上下左右的键值
      if(e.code == "ArrowLeft") alert("a");
      }
    • onkeypress
      • keydown 可以检测所有键盘按键(除了 fn), keypress 只可以检测字符类按键(ascii 码表里有的字符)
      • keypress 有 e.charCode 属性值, 它可以判断你按的是按钮 a 还是 A 或者你按的是 b
        document.onkeypress = function(e){console.log( String.fromCharCode(e.charCode));} //把 unicode 编码转换成字符
      • e.which 可以检测你按了哪个按键 一共 108个数,但是检测不了你按的是 a 还是 A
    • 触发顺序 down, press, up
      连续按的时候不抬起会连续触发 down, press 不是只触发一次
      这样魔兽世界就能开始连续跑了
  • 鼠标事件
    • onmouseenter(onmouseover)/ onmouseleave(onmouseout) 鼠标移入,鼠标移出 (out over 是老版本的)
      画板,刮刮乐 Demo
      <style type="text/css"> 
          li{
              box-sizing: border-box; /*让元素加上 border 之后仍然等于 width*/
              float: left;
              width: 10px;
              height: 10px;
              border:1px solid black;
          }
          ul#aaa{
              list-style: none;
              width: 100;
              height: 100px;
          }
      </style> 
      <ul id="aaa"> 
      <li img-date="0"> img-date 自定义属性</li> 
      <li img-date="0"></li> 
      <li img-date="0"></li> 
      <li img-date="0"></li> 
      <li img-date="0"></li> 
      </ul> 
      var myUl = document.getElementById("aaa"); 
      myUl.onmouseover = function(e) { 
          var event = e || window.event; //兼容 IE 
          var target = event.target || event.srcElement; //事件源绑定,就相当于操作 ul 里的每个 li 所以这是一个鼠标滑过 li 每个单独的 
          target.style.backgroundColor = "rgb(255, 255," + target.getAttribute('img-date') + ")"; 
          //正常应该是 background-color, 为啥用驼峰写法? 因为 JS 不允许有带 - 的属性名 mydiv.className = "aa";
          var now_date = parseInt(target.getAttribute('img-date')) + 20;   
          target.setAttribute('img-date', now_date); 
      } 、
      
      
      点击第一个 li 输出 0, 第二个输出 1...
      
      var liArr = document.getElementsByTagName("li"),
          len = liArr.length;
      for (var i = 0; i <= len, i++){
          (function(i){
              liArr[i].onclick = function(){console.log(i);}
          }(i));
          //注意这里要用立即执行函数来锁定 i 的值,在立即执行函数里 i 是形参,立即执行函数里有自己的 AO
          //如果事件在循环里,但是事件里用不到 i 那么这个类似闭包其实也不要紧,不用立即执行函数也行
      }
      也可以用事件委托来处理
      
    • onmousemove: 鼠标在元素内移动
      利用 onmouseenter/onmouseover, onmouseleave/onmouseout 和 onmousemove 写一个拖拽小方块儿的功能
          window.onload = function() {
      
              var myDiv = document.getElementsByTagName("div")[0];
      
              drag(myDiv);
      
              function drag(elem) {
                  var disX,
                      disY;
      
                  Element.prototype.addEvent = function(type, handle) { //封装添加事件函数
                      if (this.addEventListener) {
                          this.addEventListener(type, handle, false);
                      } else if (this.attachEvent) {
                          this.attachEvent('on' + type, function() {
                              handle.call(this); //处理 IE this 指向 window 的 bug
                          });
                      } else {
                          this['on' + type] = handle;
                      }
                  }
      
                  Document.prototype.addEvent = Element.prototype.addEvent;
      
                  elem.addEvent("mousedown", function(e) {
      
                      //鼠标点击 div 之后才绑定 onmousemove onmouseup 事件
                      var event = e || window.event;
                      disX = event.pageX - parseInt(this.style.left);
                      disY = event.pageY - parseInt(this.style.top);
                      //鼠标点击的点 - div 距离左边的距离,等于鼠标相对 div 内部的距离,这样才能让鼠标拖拽的时候始终保持在开始点击的位置
      
                      document.addEvent("mousemove", function(e) { //鼠标点拖
                          var event = e || window.event;
                          elem.style.left = event.pageX - disX + "px";
                          elem.style.top = event.pageY - disY + "px";
                      });
      
                      document.addEvent("mouseup", function() { //鼠标放手
                          document.onmousemove = null;
                      });
      
                      
      
                      stopBubble(event); //阻止冒泡
                      cancelHander(event); //阻止默认事件
      
                      function stopBubble(event)
                      {
                          if(event.stopPropagation){event.stopPropagation();} 
                          else {event.cancleBubble = true;}
                      }
      
                      封装一个函数,阻止默认事件
                      function cancelHander(e){
                          if(e.preventDefault) {e.preventDefault();}
                          else (e.returnValue = false;)
                      }
      
                  });
              }
          }
      Tips : div 设置了 position 才有 left,top 属性, position: absolution;   
      
      
      
      
      
      区分拖拽和点击
      Tips: 触发顺序 down, up, click 和绑定顺序没有关系
      var firstTime = 0,
          lastTime = 0;
          key = false;
      button.addEvent("click", function() { 
          if(key){
              ...执行点击事件
              key = false;
          }              
      });
      button.addEvent("onmousedown", function() { 
          firstTime = newDate().getTime();               
      });
      button.addEvent("onmouseup", function() { 
          lastTime = newDate().getTime();   
          if(lastTime - firstTime < 300){ //时间短了算点击
              key = true;
          } //时间长了算拖拽
      });
      
    • onmousedown/onmouseup == click : 鼠标按下/鼠标抬起
      触发顺序 down, up, click 和绑定顺序没有关系
      • e.button; 区分鼠标左右键,只有 "onmousedown/onmouseup" 事件能区分鼠标按键,其他都不可能
        0 1 2 左中右
        DOM3 标准规定, click 事件只能监听左键。
      • 移动端 onmousedown,onmousemove,onmouseup 就不好用了,我们要写另外的事件 touchstart touchmove, touchend
    • contextmenu //右键弹出菜单事件
  • 文本类操作事件
    • oninput : input 控件的事件,但凡input的文本有变化,无论增加还是删除,都会触发该事件
    • onchange HTML 元素改变并且对比 input 框获得焦点和失去焦点的值不一致才触发
    • onblur 失去焦点
    • onfocus 得到焦点
    • <input type="text" style="color:#999;" value="请输入用户名" οnfοcus="if(this.value=='请输入用户名'){this.value=''; this.style.color='#424242';}" οnblur="if(this.value==''){this.value = '请输入用户名'; this.style.color='#999';}">
  • 窗体类操作事件
    • scroll 滚动条滚动,事件触发
      window.onscroll = function(){ getScrollOffset();//获得滚动条滚动的位置}
      fix 条位置: 一个小块儿 当前的 top 位置,加上滚动条滚动的位置, 就相当于没有动, 广告条
    • load
    • window.onload = function(){} 浏览器已完成页面的加载
      不要用,这个方法是最慢的, 效率最低
      在页面加载的时候,html 和 css 是并行一起被解析的,在解析的时候分别生成 domTree 和 cssTree 它们加合并在一起汇成了一个 renderTree (渲染树) 然后再汇成一个页面 我们把 JS 写在下边,就相当于在生成 domTree 的时候页面刚刚解析完(而不是下载完)的时候就执行 JS
      比如说 image, 图片 size 很大,解析完的意思是: 认出了这个是一个 image 标签后然后马上挂到树上去,而开启另一个新的线程,异步同时下载这个图片。
      window.onload: 要等整个页面全部解析完, domtree, css tree, render tree 就绪, 所有文档,信息,图片等全部下载完,整个页面全部就绪的时候执行。
       

      文档解析完成触发的方法:

      document.addEventListener('DOMContentLoaded',function(){...js 写法... },false);

      $(document).ready(function(){ ... 这个是jQuery 写法...})

      当然最快的方法还是直接把 js 写在页面下面
  • submit, reset, select 等事件

事件解除

  • dom.onclick = null; 解除单击事件
    实际应用,某些事件只想执行一次
    mydiv.onclick = function(){... this.onclick = null;}
  • dom.removeEventlistener(事件类型,处理函数,false);解除事件监听
    div.addEventListener('click', function(){}, false); //这种绑定匿名函数,永远清除不了
    div.addEventListener('click', test, false); //这样通过函数名来清除
  • dom.detachEvent('on' + 事件类型,处理函数)
    绑定匿名函数,则无法解除

事件处理模型

  • 事件冒泡
    • 结构上(非视觉上),嵌套关系的元素,会存在事件冒泡的功能,既同一事件,自子元素冒泡向父元素。(从代码结构看起来是自底向上)
    • focus, blur, change, submit, reset, select 等事件不冒泡
  • 事件捕获
    • 结构上(非视觉上),嵌套关系的元素,会存在事件捕获的功能,既同一事件,自父元素获取子元素(事件源元素)。 (自顶向下)
    • IE 上没有事件捕获,Chrome 是唯一一直有的浏览器,最新版本的火狐也可以
    • dom.addEventListener(事件类型,处理函数,true)
      事件监听最后的参数变成 true, 就会立刻变成事件捕获模型, false 的时候是冒泡
    • 它和冒泡事件执行顺序正好相反。如点击事件: 先执行父元素的点击事件,然后一层一层往子元素里执行
    • IE 上有一个特殊的捕获事件的方法 dom.setCapture(); 它能把这个页面上所有的其他事件,都捕获到自己身上,比如说随便点击页面其他地方,都算点了自己。 这个方法可以解决鼠标拖拽 div 太快的时候飞出去的问题,但是,我们不用它。了解即可。
      它对应的释放方法是 dom.releaseCapture();
  • 触发顺序: 先捕获,后冒泡。
    同一个对象的同一个事件类型,上面绑定了两个事件处理函数,一个是捕获一个是冒泡的执行顺序
    <div class="wraper">
        <div class="content">
            <div class="box"></div>
        </div>
    </div>
    
    var wraper=document.getElementsByClassName('wraper')[0];
    var content=document.getElementsByClassName('content')[0];
    var box=document.getElementsByClassName('box')[0];
    
    wraper.addEventListener('click',function(){
         console.log("wraperBulle");
    },false);
    content.addEventListener('click',function(){
         console.log("contentBubble");
    },false);
    box.addEventListener('click',function(){
         console.log("boxBubble");
    },false);
    
    //事件捕获
    wraper.addEventListener('click',function(){
         console.log("wraper");
    },true);
    content.addEventListener('click',function(){
         console.log("content");
    },true);
    box.addEventListener('click',function(){
         console.log("box");
    },true);
    
    
    运行结果
    wraper
    content
    boxBubble //这里不是先执行捕获么? 为何先执行了冒泡?
    box
    contentBubble
    wraperBulle
    
    //点击 box 是这样的: 它的执行是这样的,先捕获 wraper, 然后捕获 content, 然后是 box 区域的事件执行, 然后冒泡到 content 再冒泡到 wraper.
    //这里 box 区域是两个事件执行, 事件执行的顺序要符合:谁先绑定,谁先执行。
    
      
                            

取消冒泡事件和阻止默认事件

  • 取消冒泡

    • W3C event.stopPropagation(); 但不支持 ie9 以下版本
    • IE 独有 event.cancleBubble = true; (目前谷歌也能实现了)
    • 封装阻止冒泡的函数,兼容
      function stopBubble(event)
      {
          if(event.stopPropagation){event.stopPropagation();} 
          else {event.cancleBubble = true;}
      }
      
      div.onclick = function(e){
          var event = e || window.event; //兼容 IE
          stopPropagation(e);
      }
      在每一个事件处理函数中,可以写一个形参:事件对象 e, 写多了也没有用,我们不用传东西,系统会自动帮我们传  
                                      
  • 阻止默认事件

    • 默认事件: 表单提交,a 标签跳转,鼠标右键出菜单等...
    • return false; 以对象的方式注册的事件才生效, 也就是它值适用于 on## = function(){} 产生的事件,不适用于 addEventListener 或者 attachEvent 产生的事件

      取消鼠标右键出菜单事件
      document.oncontextmenu = function(){console.log("a");} //此时鼠标右键既出菜单,又打印 a
      document.oncontextmenu = function(){console.log("a"); return false;} //此时右键不出菜单,只打印 a

    • e.preventDefault(); W3C 标准
    • e.returnValue = false; IE 浏览器使用
    • 封装一个函数,阻止默认事件
      function cancelHander(e){
          if(e.preventDefault) {e.preventDefault();}
          else (e.returnValue = false;)
      }
      document.oncontextmenu = function(e){
          console.log("a"); 
          cancelHander(e);// 取消右键弹出菜单
      }
  • 我们经常拿 a 标签当做按钮来用,我们如何取消 a 标签的跳转或者刷新页面的功能
    方法 一: <a href="http://www.ibm.com/..." οnclick="aa();"></a>
    function aa(){
    ...
    return false;
    }

    方法二:
    a 标签 href= 里可以写协议限定符 javascrip: 这样后面的就是 js 代码
    (比如 <a href="javascrip:alert('a')">),
    在标签的行间里写 void 相当于直接写返回值, void(0)/void(false) 都相当于 return false;
    <a href="javascrip:void(0)" οnclick="aa();"></a>

事件源对象 e

  • IE 浏览器没有 e 对象
    div.onclick = function(e){
    var event = e || window.event; //兼容 IE
    }
  • e.clientX/PageX; e.clientY/PageY; 鼠标点击事件的时候所点击的坐标点
  • var target = event.target || event.srcElement; //事件源绑定兼容性写法
    父子元素, 点击父元素(没有碰到子元素),事件源才是父元素, 如果点击的是子元素,是通过冒泡或者事件捕获到了父元素的,那么事件源是子元素
    • event.target 火狐只有这个
    • event.srcElement IE 只有这个
    • Chrome 都有
  • e.button; 区分鼠标左右键,只有 "onmousedown/onmouseup" 事件能区分鼠标按键,其他都不可能
    0 1 2 左中右

事件委托

  • 事件委托:利用事件冒泡,和事件源对象进行处理
    让自己的所触发的事件,让他的父元素代替执行!
  • 实际应用:就是一个 ul 有 一百万个 li,点击li 打印li 里的内容。 并且之后动态添加了 li 会自动被添加事件
    myUl.onclick = function(e) { 
        var event = e || window.event; 
        var target = event.target || event.srcElement; 
        console.log(target.innerText);  
    }
  • 优点
    • 性能: 不需要循环所有子元素一个一个绑定事件,效率高
    • 灵活: 当动态添加子元素时,不需要重新绑定事件,可扩展性好
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值