[TOC]

绑定事件的两种方式/DOM事件的级别

我们在之前的一篇文章《04-JavaScript/22-DOM简介和DOM操作》中已经讲过事件的概念。这里讲一下绑定(注册)事件的两种方式,我们以onclick事件为例。

DOM0的写法:onclick

    element.onclick = function () {

    }

举例:

<body>
<button>点我</button>
<script>
    var btn = document.getElementsByTagName("button")[0];

    //这种事件绑定的方式,如果绑定多个,则后面的会覆盖掉前面的
    btn.onclick = function () {
        console.log("事件1");
    }

    btn.onclick = function () {
        console.log("事件2");
    }

</script>
</body>

点击按钮后,上方代码的打印结果:

事件2

我们可以看到,DOM对象.事件 = 函数的这种绑定事件的方式:一个元素的一个事件只能绑定一个响应函数。如果绑定了多个响应函数,则后者会覆盖前者。

DOM2的写法:addEventListener(高版本浏览器)

    element.addEventListener('click', function () {

    }, false);

参数解释:

  • 参数1:事件名的字符串(注意,没有on)
  • 参数2:回调函数:当事件触发时,该函数会被执行
  • 参数3:true表示捕获阶段触发,false表示冒泡阶段触发(默认)。如果不写,则默认为false。【重要】

举例:

<body>
<button>按钮</button>
<script>
    var btn = document.getElementsByTagName("button")[0];

    // addEventListener: 事件监听器。 原事件被执行的时候,后面绑定的事件照样被执行
    // 这种写法不存在响应函数被覆盖的情况。(更适合团队开发)
    btn.addEventListener("click", fn1);
    btn.addEventListener("click", fn2);

    function fn1() {
        console.log("事件1");
    }

    function fn2() {
        console.log("事件2");
    }

</script>
</body>

点击按钮后,上方代码的打印结果:

    事件1
    事件2

我们可以看到,addEventListener()这种绑定事件的方式:

  • 一个元素的一个事件,可以绑定多个响应函数。不存在响应函数被覆盖的情况。执行顺序是:事件被触发时,响应函数会按照函数的绑定顺序执行。
  • addEventListener()中的this,是绑定事件的对象。
  • addEventListener()不支持 IE8 及以下的浏览器。在IE8中可以使用attachEvent来绑定事件(详见下一小段)。

DOM2的写法:attachEvent(IE8及以下版本浏览器)

    element.attachEvent('onclick', function () {

    });

参数解释:

  • 参数1:事件名的字符串(注意,有on)
  • 参数2:回调函数:当事件触发时,该函数会被执行

举例:

    <body>
        <button>按钮</button>
        <script>
            var btn = document.getElementsByTagName('button')[0];

            btn.attachEvent('onclick', function() {
                console.log('事件1');
            });

            btn.attachEvent('onclick', function() {
                console.log('事件2');
            });
        </script>
    </body>

在低版本的IE浏览器上,点击按钮后,上方代码的打印结果:

    事件2
    事件1

我们可以看到,attachEvent()这种绑定事件的方式:

  • 一个元素的一个事件,可以绑定多个响应函数。不存在响应函数被覆盖的情况。注意:执行顺序是,后绑定的先执行。
  • attachEvent()中的this,是window

兼容性写法

上面的内容里,需要强调的是:

  • addEventListener()中的this,是绑定事件的对象。
  • attachEvent()中的this,是window。

既然这两个写法的this不同,那么,有没有一种兼容性的写法可以确保这两种绑定方式的this是相同的呢?我们可以封装一下。代码如下:

    <body>
        <button>按钮</button>
        <script>
            var btn = document.getElementsByTagName('button')[0];

            myBind(btn , "click" , function(){
                alert(this);
            });



            //定义一个函数,用来为指定元素绑定响应函数
            /*
             * addEventListener()中的this,是绑定事件的对象
             * attachEvent()中的this,是window
             *  需要统一两个方法this
             */
            /*
             * 参数:
             *  element 要绑定事件的对象
             *  eventStr 事件的字符串(不要on)
             *  callback 回调函数
             */
            function myBind(element , eventStr , callback){
                if(element.addEventListener){
                    //大部分浏览器兼容的方式
                    element.addEventListener(eventStr , callback , false);
                }else{
                    /*
                     * this是谁,由调用方式决定
                     * callback.call(element)
                     */
                    //IE8及以下
                    element.attachEvent("on"+eventStr , function(){
                        //在匿名函数 function 中调用回调函数callback
                        callback.call(element);
                    });
                }
            }

        </script>
    </body>

事件对象

当事件的响应函数被触发时,会产生一个事件对象event。浏览器每次都会将这个事件event作为实参传进之前的响应函数。
这个对象中包含了与当前事件相关的一切信息。比如鼠标的坐标、键盘的哪个按键被按下、鼠标滚轮滚动的方向等。

获取 event 对象(兼容性问题)

所有浏览器都支持event对象,但支持的方式不同。如下。
(1)普通浏览器的写法是 event。比如:
45-事件的绑定和事件对象Event - 图1
(2)ie 678 的写法是 window.event。此时,事件对象 event 是作为window对象的属性保存的。
于是,我们可以采取一种兼容性的写法。如下:

    event = event || window.event; // 兼容性写法

代码举例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script>
    //点击页面的任何部分
    document.onclick = function (event) {
        event = event || window.event; ////兼容性写法

        console.log(event);
        console.log(event.timeStamp);
        console.log(event.bubbles);
        console.log(event.button);
        console.log(event.pageX);
        console.log(event.pageY);
        console.log(event.screenX);
        console.log(event.screenY);
        console.log(event.target);
        console.log(event.type);
        console.log(event.clientX);
        console.log(event.clientY);
    }
</script>
</body>
</html>

event 属性

event 有很多属性,比如:
45-事件的绑定和事件对象Event - 图2
由于pageX 和 pageY的兼容性不好,我们可以这样做:

  • 鼠标在页面的位置 = 滚动条滚动的距离 + 可视区域的坐标。

    Event举例

    举例1:使 div 跟随鼠标移动

    代码实现: ``` <!DOCTYPE html>

### 举例2:获取鼠标距离所在盒子的距离
关键点:
鼠标距离所在盒子的距离 = 鼠标在整个页面的位置 - 所在盒子在整个页面的位置
代码演示:

<!DOCTYPE html>

实现效果:<br />![](http://img.smyhvae.com/20180203_1828.gif)
### 举例3:商品放大镜
代码实现:<br />(1)index.html:

<!DOCTYPE html>

45-事件的绑定和事件对象Event - 图3
45-事件的绑定和事件对象Event - 图4
(2)tools.js:

/**

  • Created by smyhvae on 2018/02/03. */

//显示和隐藏 function show(ele) { ele.style.display = “block”; }

function hide(ele) { ele.style.display = “none”; }

function scroll() { // 开始封装自己的scrollTop if (window.pageYOffset != null) { // ie9+ 高版本浏览器 // 因为 window.pageYOffset 默认的是 0 所以这里需要判断 return { left: window.pageXOffset, top: window.pageYOffset } } else if (document.compatMode === “CSS1Compat”) { // 标准浏览器 来判断有没有声明DTD return { left: document.documentElement.scrollLeft, top: document.documentElement.scrollTop } } return { // 未声明 DTD left: document.body.scrollLeft, top: document.body.scrollTop } }

``` 效果演示:
45-事件的绑定和事件对象Event - 图5

我的公众号

想学习代码之外的技能?不妨关注我的微信公众号:千古壹号(id:qianguyihao)。
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
45-事件的绑定和事件对象Event - 图6