javascript中的一些核心知识点(三)javascript中的DOM事件

事件流

javascript注册dom事件的手段很多:

① 直接写在dom标签上,onclick的做法

② 在js中这样写:el.onclick = function

上述做法事实上是不好的,因为他们无法多次定义,也无法注销,更加不用说使用事件委托机制了

上述两种做法的最终仍然是调用addEventListener方式进行注册冒泡级别的事件,于是这里又扯到了javascript事件的几个阶段

在DOM2级事件定义中规定事件包括三个阶段,这个是现有DOM事件的基础,这个一旦改变,前端DOM事件便需要重组
三个阶段是事件事件捕获阶段、处于目标阶段、冒泡阶段
事件捕获由最先接收到事件的元素往最里面传
事件冒泡由最具体元素往上传至document

一般而言是先捕获后冒泡,但是处于阶段的事件执行只与注册顺序有关,比如:
每次点击一个DOM时候我们会先判断是否处于事件阶段,若是到了处于阶段的话便不存在捕获阶段了
直接按照这个DOM的事件注册顺序执行,然后直接进入冒泡阶段逻辑,其判断的依旧是e.target与e.currentTarget是否相等

这个涉及到一个浏览器内建事件对象,我们注册事件方式多种多样
除了addEventListener可以注册捕获阶段事件外,其余方式皆是最后调用addEventListener接口注册冒泡级别事件
注册的事件队列会根据DOM树所处位置进行排列,最先的是body,到最具体的元素
每次我们点击页面一个区域便会先做判断,是否处于当前阶段,比如:
我当前就是点击的是一个div,如果e.target==e.currentTarget,这个时候便会按注册顺序执行其事件,不会理会事件是捕获还是冒泡,而跳过捕获流程,结束后会执行冒泡级别的事件,若是body上有冒泡点击事件(没有捕获)也会触发,以上便是DOM事件相关知识点

事件冒泡是事件委托实现的基石,我们在页面的每次点击最终都会冒泡到其父元素,所以我们在document处可以捕捉到所有的事件,事件委托实现的核心知识点是解决以下问题:

① 我们事件是绑定到document上面,那么我怎么知道我现在是点击的什么元素呢

② 就算我能根据e.target获取当前点击元素,但是我怎么知道是哪个元素具有事件呢

③ 就算我能根据selector确定当前点击的哪个元素需要执行事件,但是我怎么找得到是哪个事件呢

如果能解决以上问题的话,我们后面的流程就比较简单了

确定当前元素使用 e.target即可,所以我们问题以解决,其次便根据该节点搜索其父节点即可,发现父节点与传入的选择器有关便执行事件回调即可

这里还需要重新e.currentTarget,不重写全部会绑定至document,简单实现:

var arr = [];
var slice = arr.slice;
var extend = function (src, obj) {
  var o = {};
  for (var k in src) {
    o[k] = src[k];
  }
  for (var k in obj) {
    o[k] = obj[k];
  }
  return o;
};

function delegate(selector, type, fn) {
  var callback = fn;

  var handler = function (e) {
    //选择器找到的元素
    var selectorEl = document.querySelector(selector);
    //当前点击元素
    var el = e.target;
    //确定选择器找到的元素是否包含当前点击元素,如果包含就应该触发事件
    /*************
    注意,此处只是简单实现,实际应用会有许多判断
    *************/
    if (selectorEl.contains(el)) {
      var evt = extend(e, { currentTarget: selectorEl });
      evt = [evt].concat(slice.call(arguments, 1));
      callback.apply(selectorEl, evt);
      var s = '';
    }
    var s = '';
  };

  document.addEventListener(type, handler, false);
}

事件委托由于全部事件是绑定到document上的,所以会导致阻止冒泡失效,很多初学的同学不知道,这里要注意

事件模拟


事件模拟是dom事件的一种高级应用,一般情况下用不到,但是一些极端情况下他是解决实际问题的杀手锏

事件模拟是javascript事件机制中相当有用的功能,理解事件模拟与善用事件模拟是判别一个前端的重要依据,所以各位一定要深入理解

事件一般是由用户操作触发,其实javascript也是可以触发的,比较重要的是,javascript模拟的触发遵循事件流机制!!!

意思就是,javascript触发的事件与浏览器本身触发其实是一样的,简单模拟事件点击:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <style type="text/css">
         #p { width: 300px; height: 300px; padding: 10px;  border: 1px solid black; }
         #c { width: 100px; height: 100px; border: 1px solid red; }
    </style>
</head>
<body>
    <div id="p">
        parent
        <div id="c">
            child
        </div>
    </div>
    <script type="text/javascript">
        alert = function (msg) {
            console.log(msg);
        }

        var p = document.getElementById('p'),
        c = document.getElementById('c');
        c.addEventListener('click', function (e) {
            console.log(e);
            alert('子节点捕获')
        }, true);
        c.addEventListener('click', function (e) {
            console.log(e);
            alert('子节点冒泡')
        }, false);

        p.addEventListener('click', function (e) {
            console.log(e);
            alert('父节点捕获')
        }, true);

        p.addEventListener('click', function (e) {
            console.log(e);
            alert('父节点冒泡')
        }, false);

        document.addEventListener('keydown', function (e) {
            if (e.keyCode == '32') {
                var type = 'click'; //要触发的事件类型
                var bubbles = true; //事件是否可以冒泡
                var cancelable = true; //事件是否可以阻止浏览器默认事件
                var view = document.defaultView; //与事件关联的视图,该属性默认即可,不管
                var detail = 0;
                var screenX = 0;
                var screenY = 0;
                var clientX = 0;
                var clientY = 0;
                var ctrlKey = false; //是否按下ctrl
                var altKey = false; //是否按下alt
                var shiftKey = false;
                var metaKey = false;
                var button = 0; //表示按下哪一个鼠标键
                var relatedTarget = 0; //模拟mousemove或者out时候用到,与事件相关的对象
                var event = document.createEvent('Events');
                event.myFlag = '叶小钗';
                event.initEvent(type, bubbles, cancelable, view, detail, screenX, screenY, clientX, clientY,
ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
                
                console.log(event);
                c.dispatchEvent(event);
            }
        }, false);
    </script>
</body>
</html>

模拟点击事件是解决移动端点击响应的基石。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值