冒泡捕获流 事件源对象 鼠标行为(坐标) 封装多功能事件函数(拖拽元素 唤出menu 双击事件elemClick) 事件委托

冒泡捕获流

事件流:描述从页面中接收事件的顺序: 冒泡 捕获
IE 提出的 事件冒泡流(Event Bubbing)
Netspace 提出的 事件捕获流(Event Capturing)
分为三个阶段 顺序 事件捕获阶段 处于目标阶段 冒泡阶段

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .wrapper {
        width: 300px;
        height: 300px;
        background-color: green;
      }
      .outer {
        width: 200px;
        height: 200px;
        background-color: red;
      }
      .inner {
        width: 100px;
        height: 100px;
        background-color: orange;
      }
    </style>
  </head>
  <body>
    <div class="wrapper">
      <div class="outer">
        <div class="inner"></div>
      </div>
    </div>
    <script>
      var wrapper = document.getElementsByClassName('wrapper')[0],
        outer = wrapper.getElementsByClassName('outer')[0],
        inner = outer.getElementsByClassName('inner')[0];
      wrapper.addEventListener(
        'click',
        function () {
          console.log('捕获wrapper');
        },
        true
      );
      outer.addEventListener(
        'click',
        function () {
          console.log('捕获outer');
        },
        true
      );
      inner.addEventListener(
        'click',
        function () {
          console.log('目标(捕获)inner');
        },
        true
      );
      wrapper.addEventListener(
        'click',
        function () {
          console.log('冒泡wrapper');
        },
        false
      );
      outer.addEventListener(
        'click',
        function () {
          console.log('冒泡outer');
        },
        false
      );
      inner.addEventListener(
        'click',
        function () {
          console.log('目标(冒泡)inner');
        },
        false
      );
    </script>
  </body>
</html>

在这里插入图片描述

事件源对象

target srcElement 事件源对象
火狐只有target
IE只有srcElement

  <body>
    <div>哈哈哈</div>
    <script>
      var oDiv = document.getElementsByTagName('div')[0];
      oDiv.onclick = function (e) {
        console.log(e);
      };
    </script>
  </body>

在这里插入图片描述

事件委托

点击li获取li的内容 这是就要循环遍历li 给每一个li都绑定上click事件
但是当点击按钮增加一个新的li时 又要手动绑定事件
当li非常多的时候这种方法是不可取的
此时就要把点击事件委托给父级ul 通过事件冒泡的形式 来优化

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style></style>
  </head>
  <body>
    <button>增加</button>
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
      <li>6</li>
      <li>7</li>
      <li>8</li>
      <li>9</li>
      <li>10</li>
    </ul>
    <script>
      var oList = document.getElementsByTagName('ul')[0],
        oLi = oList.getElementsByTagName('li'),
        oBtn = document.getElementsByTagName('button')[0],
        len = oLi.length,
        item;
      oList.onclick = function (e) {
        var e = e || window.event,
          tar = e.target || e.srcElement;
        console.log(tar.innerText);
      };
      oBtn.onclick = function () {
        var li = document.createElement('li');
        li.innerText = oLi.length + 1;
        oList.appendChild(li);
      };
    </script>
  </body>
</html>

在这里插入图片描述

获取所点击li元素的下标
下面很多人会想到的方法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style></style>
  </head>
  <body>
    <button>增加</button>
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
      <li>6</li>
      <li>7</li>
      <li>8</li>
      <li>9</li>
      <li>10</li>
    </ul>
    <script>
      var oList = document.getElementsByTagName('ul')[0],
        oLi = oList.getElementsByTagName('li'),
        len = oLi.length,
        item;
      oList.onclick = function (e) {
        var e = e || window.event,
          tar = e.target || e.srcElement;
        for (var i = 0; i < len; i++) {
          item = oLi[i];
          if (tar === item) {
            console.log(i);
          }
        }
      };
    </script>
  </body>
</html>

在这里插入图片描述

这里推荐一种方法 使用indexOf
因为indexOf是数组上的方法 而获取到的li是类数组所不能直接使用 需要使用下面的方式
Array.prototype.indexOf.call(DOM对象集合, 当前事件源)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style></style>
  </head>
  <body>
    <button>增加</button>
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
      <li>6</li>
      <li>7</li>
      <li>8</li>
      <li>9</li>
      <li>10</li>
    </ul>
    <script>
      var oList = document.getElementsByTagName('ul')[0],
        oLi = oList.getElementsByTagName('li'),
        len = oLi.length,
        item;
      oList.onclick = function (e) {
        var e = e || window.event,
          tar = e.target || e.srcElement;
        var index = Array.prototype.indexOf.call(oLi, tar);
        console.log(index);
      };
    </script>
  </body>
</html>

在这里插入图片描述

鼠标行为

clientX/Y 鼠标位置相对于当前可视区域的坐标 不包括滚动条的距离
layerX/Y 同pageX/Y相同 IE11下同clientX/Y
screenX/Y 鼠标位置相对于屏幕的坐标
X/Y 与clientX/Y相同
pageX/pageY 鼠标位置相对于当前文档的坐标 包含滚动条的距离 IE9下不支持
offsetX/Y 鼠标位置相对于块元素的坐标 包含边框

鼠标按键

e.button
左0 中1 右2
mouseUp 与 mouseDowm可以检测到鼠标按键事件

封装获取鼠标相对于可视区域坐标的方法

这里我们使用之前文章封装过的获取滚动条距离的函数getScrollOffset

      function pagePos(e) {
        var sLeft = getScrollOffset().left,
          sTop = getScrollOffset().top,
          cLeft = document.documentElement.clientLeft || 0,
          cTop = document.documentElement.clientTop || 0;
        return {
          X: e.clientX + sLeft - cLeft,
          Y: e.clientY + sTop - cTop,
        };
      }

封装多功能事件函数(拖拽元素 唤出menu 双击事件elemClick)

功能
单击拖拽元素 右击唤出menu 双击开启事件elemClick
这里使用我们之前文章封装过的获取元素样式属性值的函数getStyles
还有之前文章封装的添加事件的方法addEvent和取消事件的removeEvent
阻止默认事件的preventDefaultEvent取消冒泡的cancelBubble
还有上文获取鼠标相对于可视窗口坐标的pagePos

      Element.prototype.dragNclick = function (menu, elemClick) {
        var bTime = 0,
          eTime = 0,
          oPos = [],
          //双击开始时间
          cbTime = 0,
          ceTime = 0,
          // 点击次数
          counter = 0,
          t = null,
          // 页面的宽高
          wWidth = getViewportSize().width,
          wHeight = getViewportSize().height,
          //元素的宽高
          eleWidth = getStyles(this, 'width'),
          eleHeight = getStyles(this, 'height'),
          mWidth = getStyles(menu, 'width'),
          mHeight = getStyles(menu, 'height');
        drag.call(this);
        function drag() {
          var x,
            y,
            _self = this;
          addEvent(this, 'mousedown', function (e) {
            var e = e || window.event,
              btnCode = e.button;
            if (btnCode === 2) {
              var mLeft = pagePos(e).X,
                mTop = pagePos(e).Y;
              if (mLeft <= 0) {
                mLeft = 0;
              } else if (mLeft >= wWidth - mWidth) {
                mLeft = pagePos(e).X - mWidth;
              }
              if (mTop <= 0) {
                mTop = 0;
              } else if (mTop >= wHeight - mHeight) {
                mTop = pagePos(e).Y - mHeight;
              }
              menu.style.left = mLeft + 'px';
              menu.style.left = mTop + 'px';
              menu.style.display = 'block';
            } else if (btnCode === 0) {
              bTime = new Date().getTime();
              oPos = [getStyles(_self, 'left'), getStyles(_self, 'top')];
              menu.style.display = 'none';
              x = pagePos(e).X - getStyles(_self, 'left');
              y = pagePos(e).Y - getStyles(_self, 'top');
              addEvent(document, 'mousemove', mouseMove);
              addEvent(document, 'mouseup', mouseUp);
              cancelBubble(e);
              preventDefaultEvent(e);
            }
          });
          addEvent(document, 'contextmenu', function (e) {
            var e = e || window.event;
            preventDefaultEvent(e);
          });
          addEvent(document, 'click', function (e) {
            menu.style.display = 'none';
          });
          addEvent(menu, 'click', function (e) {
            var e = e || window.event;
            cancelBubble(e);
          });
          function mouseMove(e) {
            var e = e || window.event,
              eleLeft = pagePos(e).X - x,
              eleTop = pagePos(e).Y - y;
            // 如果鼠标离开了左侧
            if (eleLeft <= 0) {
              eleLeft = 0;
              // 如果鼠标距离元素左边界的距离大于页面的宽度减去元素距离左侧的距离 就不变 使元素靠在最右侧
            } else if (eleLeft >= wWidth - eleWidth) {
              eleLeft = wWidth - eleWidth;
            }
            if (eleTop <= 0) {
              eleTop = 0;
            } else if (eleTop >= wHeight - eleHeight) {
              eleTop = wHeight - eleHeight;
            }
            _self.top = pagePos(e).X - x + 'px';
            _self.left = pagePos(e).Y - y + 'px';
          }
          function mouseUp(e) {
            var e = e || window.event;
            eTime = new Date().getTime();
            if (eTime - bTime < 100) {
              _self.left = oPos[0] + 'px';
              _self.top = oPos[1] + 'px';
              counter++;
              if (counter === 1) {
                cbTime = new Date().getTime();
              }
              if (counter === 2) {
                ceTime = new Date().getTime();
              }
              if (cbTime && ceTime && ceTime - bTime < 200) {
                elemClick();
              }
              t = setTimeout(function () {
                ebTime = 0;
                ceTime = 0;
                counter = 0;
                clearTimeout(t);
              }, 200);
            }
            removeEvent(document, 'mousemove', mouseMove);
            removeEvent(document, 'mouseup', mouseUp);
          }
        }
      };
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_聪明勇敢有力气

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值