JavaScript课程——Day12(事件基础、事件绑定与取消、DOM事件流、事件委托行为、事件委托、键盘事件、滚轮事件)

1、事件基础

  1.1、事件函数

  • 当事件被触发时调用的函数就是事件函数
function fn() {
    console.log('我执行了');
}

div.onclick = fn; // fn是一个事件函数

fn(); // fn不是事件函数

  1.2、事件对象

  • 事件对象:当一个事件发生的时候,跟这个事件有关的一些信息保存在一个全局的event对象中,这个对象就是事件对象。
  • IE和谷歌:全局的event对象
  • 标准浏览器:事件函数的第一个函数
  • 兼容:IE9及以上,用事件函数的第一个参数,IE8及以下,用全局的event
var box = document.getElementById('box');

box.onclick = function (ev) {
    // console.log(event); // IE和谷歌
    // console.log(ev); // 标准浏览器
    var ev = ev || event; // 兼容
    console.log(ev); // 事件对象

    // 事件对象详情
    console.log(ev.type); // 事件类型
    // console.log(ev.target); // 事件源,IE8及以下不支持
    // console.log(ev.srcElement); // 事件源,IE8及以下支持
    var target = ev.target || ev.srcElement; // 事件源兼容
    target.style.background = 'yellow';

    console.log(ev.clientX, ev.clientY); // 鼠标相对可视区的距离
    console.log(ev.pageX, ev.pageY); // 鼠标相对文档的距离(IE8及以下不支持)

    console.log(ev.altKey); // 事件发生的时候,alt键是否按下
    console.log(ev.shiftKey); // 事件发生的时候,shift键是否按下
    console.log(ev.ctrlKey); // 事件发生的时候,ctrl键是否按下
}

2、事件绑定与取消

  2.1、事件绑定

  • 格式:元素.addEventListener(不要on的事件名,函数,是否捕获);                    IE9及以上支持
  • 格式:元素.attachEvent(要on的事件名,函数);                                                IE8及以下支持
<script>
    // 需求:给同一个元素的同一个事件添加不同的处理函数
    var box = document.getElementById('box');
    function fn1() {
        console.log(this === window);
        console.log(1);
    }
    function fn2() {
        console.log(2);
    }

    // 赋值的写法,后面的覆盖前面的
    box.onclick = fn1;
    box.onclick = fn2;

    // ---------------------------------------------
    // IE9及以上支持
    // Listener 监听
    // 格式:元素.addEventListener(不要on的事件名, 函数, 是否捕获);
    // 第三个参数默认为false,false冒泡,true捕获
    box.addEventListener('click', fn1, false);
    box.addEventListener('click', fn2, false);

    // ----------------------------------------
    // IE8及以下
    // 格式:元素.attachEvent(要on的事件名, 函数);
    box.attachEvent('onclick', fn1);
    box.attachEvent('onclick', fn2);

    // ---------------------------------------------
    // 区别:
    // 1、ie 没有捕获,标准有捕获
    // 2、ie 的事件名称前面有 on,标准没有
    // 3、标准的会根据事件的顺序正序执行,IE逆序执行
    // 4、ie 的 this 是 window,标准的是触发这个事件的对象

    // ---------------------------
    // 兼容原理(浏览器能力判断)
    // console.log(box.addEventListener); // IE9及以上返回一个函数,IE8及以下返回undefined
    if (box.addEventListener) {
        // IE9及以上
        box.addEventListener('click', fn1, false);
        box.addEventListener('click', fn2, false);
    } else {
        // IE8及以下
        box.attachEvent('onclick', fn1);
        box.attachEvent('onclick', fn2);
    }

    // --------------------------------
    // 事件绑定封装
    function bind(ele, event, callback) {
        if (ele.addEventListener) {
            // IE9及以上
            ele.addEventListener(event, callback, false);
        } else {
            // IE8及以下
            ele.attachEvent('on' + event, callback);
        }
    }
    bind(box, 'click', fn1);
    bind(box, 'click', fn2);
</script>

  2.2、取消事件绑定

  标准浏览器

  • 绑定格式:元素.addEventListener(不要on的事件名,函数,是否捕获);
  • 解绑格式:元素.removeEventListenter(不要on的事件名,函数,是否捕获);

  IE8及以下

  • 绑定格式:元素.attachEvent(要on的事件名,函数);
  • 解绑格式:元素.detachEvent(要on的事件名,函数);
<script>
    // 需求:给同一个元素的同一个事件添加不同的处理函数

    var box = document.getElementById('box');
    function fn1() {
        console.log(1);
    }
    function fn2() {
        console.log(2);
    }

    // 赋值的写法,后面的覆盖前面的
    // box.onclick = fn1;
    // box.onclick = null; // 取消事件绑定

    // ---------------------------------------------
    // IE9及以上支持
    // 格式:元素.addEventListener(不要on的事件名, 函数, 是否捕获);
    // 解绑:元素.removeEventListener(不要on的事件名, 函数, 是否捕获);
    box.addEventListener('click', fn1, false);
    box.addEventListener('click', fn2, false);
    box.removeEventListener('click', fn2, false);

    // ----------------------------------------
    // IE8及以下
    // 格式:元素.attachEvent(要on的事件名, 函数);
    // 解绑:元素.detachEvent(要on的事件名, 函数);
    box.attachEvent('onclick', fn1);
    box.attachEvent('onclick', fn2);
    box.detachEvent('onclick', fn2);

    // --------------------------------
    // 事件绑定封装
    function bind(ele, event, callback) {
        if (ele.addEventListener) {
            // IE9及以上
            ele.addEventListener(event, callback, false);
        } else {
            // IE8及以下
            ele.attachEvent('on' + event, callback);
        }
    }

    // 解绑
    function unbind(ele, event, callback) {
        if (ele.removeEventListener) {
            // IE9及以上
            ele.removeEventListener(event, callback, false);
        } else {
            // IE8及以下
            ele.detachEvent('on' + event, callback);
        }
    }

    bind(box, 'click', fn1);
    bind(box, 'click', fn2);
    unbind(box, 'click', fn2); // 解绑

</script>

3、DOM事件流

  3.1、事件流

  • 事件流:当事件发生的时候,事件会按一定的顺序在根节点和各元素之间传播,所经过的节点,都会出发对应的事件。
  • 事件流分为三个阶段:
    • 1、捕获阶段:从最外层的document > html > body > box1 > box2 > box3的过程,从外到里
    • 2、处于目标阶段:到达了box3的上面
    • 3、冒泡阶段:从最里面的box3 > box2 > box1 > body > html > document的过程,从里到外
<div id="box1">
    <div id="box2">
        <div id="box3"></div>
    </div>
</div>
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');

function fn() {
    console.log(this.id);
}

box1.onclick = fn; // 这种形式的绑定,是在冒泡阶段触发
box2.onclick = fn;
box3.onclick = fn;

  3.2、捕获与冒泡

  • 冒泡,事件在子元素发生,子元素先处理,然后子元素传递到父元素
  • 捕获,事件在子元素发生,先经过父元素,父元素先处理,再分发到子元素
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');

function fn() {
    console.log(this.id);
}

box1.addEventListener('click', fn, false); // false 事件会在冒泡阶段触发
box2.addEventListener('click', fn, false); // false 事件会在冒泡阶段触发
box3.addEventListener('click', fn, false); // false 事件会在冒泡阶段触发

box1.addEventListener('click', fn, true); // true 事件会在捕获阶段触发
box2.addEventListener('click', fn, true); // true 事件会在捕获阶段触发
box3.addEventListener('click', fn, true); // true 事件会在捕获阶段触发

// --------------------------------
// 元素.事件 和 attachEvent只有冒泡(冒泡是默认存在的)
// addEventListener可以选择捕获或冒泡

  3.3、阻止冒泡

  • 标准浏览器:event.stopPropagation();
  • IE浏览器:event.cancelBubble = true;
<style>
        span {
            display: block;
            width: 100px;
            height: 30px;
            background-color: green;
            text-align: center;
            line-height: 30px;
            color: white;
            cursor: pointer;
        }

        #box {
            width: 200px;
            height: 500px;
            background-color: yellow;
            display: none;
        }
    </style>
</head>

<body>
    <span>标题</span>
    <div id="box"></div>

    <script>
        // 阻止冒泡
        // Propagation 传播    cancel取消    Bubble泡泡
        // 标准浏览器:event.stopPropagation();
        // IE 浏览器:event.cancelBubble = true;

        var span = document.querySelector('span');
        var box = document.getElementById('box');

        // 1、点击span,box展示
        span.onclick = function (ev) {
            var ev = ev || event;
            box.style.display = 'block';

            // ev.stopPropagation(); // 标准浏览器
            // ev.cancelBubble = true; // IE 浏览器
            stopPropagation(ev); // 阻止冒泡的兼容
        }

        // 2、点击页面的任何地方,box隐藏
        document.onclick = function () {
            box.style.display = 'none';
        }

        // 阻止冒泡的兼容
        function stopPropagation(ev) {
            if (ev.stopPropagation) {
                ev.stopPropagation();
            } else {
                ev.cancelBubble = true;
            }
        }
    </script>
</body>

4、事件委托行为

某些事件,即赋予了元素特殊的操作

  • 元素.事件添加的事件:return false;
  • 元素.addEventListener():ev.preventDefault();
  • 元素.attachEvent():ev.returnValue = false;
<body style="height: 3000px;">

    <a href="https://www.baidu.com">百度</a>

    <script>
        var a = document.querySelector('a');
        a.onclick = function (ev) {
            var ev = ev || event;
            preventDefault(ev);
        }

        // 阻止默认行为的兼容
        function preventDefault(ev) {
            if (ev.preventDefault) {
                ev.preventDefault();
            } else {
                ev.returnValue = false;
            }
        }
    </script>
</body>

5、事件委托

事件委托:也叫事件代理,利用事件冒泡原理,只指定一个事件处理程序,就可以管理某一类型的所有事件。

实现:事件加给父级,找到事件源,对事件源进行判断,然后做相应的操作

好处:

  • 节省性能
  • 新添加的元素也有之前的事件
<ul>
    <li>吃饭</li>
    <li>睡觉</li>
    <li>打豆豆</li>
</ul>
var ul = document.querySelector('ul');
var li = ul.getElementsByTagName('li');

// 通常做法(新添加的元素,没有之前的事件)
// for (var i = 0; i < li.length; i++) {
//     li[i].onclick = function () {
//         this.style.background = 'red';
//     }
// }

// 事件代理
ul.onclick = function (ev) {
    var ev = ev || event;
    var target = ev.target || ev.srcElement; // 事件源

    if (target.nodeName === 'LI') {
        target.style.background = 'yellow';
    }
}


// 添加一个li
var item = document.createElement('li');
item.innerHTML = '我是新来的';
ul.appendChild(item);

6、键盘事件

  6.1、键盘事件

  • onkeydown  键盘按下
  • onkeyup  键盘抬起

在能响应用户输入的元素上触发(表单元素、document都可以响应键盘事件)

var input = document.querySelector('input');

// 按下
input.onkeydown = function () {
    console.log(this.value);
}

// 抬起
input.onkeyup = function () {
    console.log(this.value);
}

  6.2、键盘事件和事件对象

var input = document.querySelector('input');

// 抬起
input.onkeyup = function (ev) {
    var ev = ev || event;
    console.log(ev);

    console.log(ev.keyCode); // 键码 按键的键码  
    // a 65   z 90    回车 13    esc 27   空格 32
    console.log(ev.key); // 键值  IE8及以下不支持

    console.log(ev.altKey);
    console.log(ev.shiftKey);
    console.log(ev.ctrlKey);
}

7、滚轮事件

标准和IE:

  • 事件:onmousewheel
  • 方向:ev.wheelDelta    上:120/150    下:-120/-150

火狐:

  • 事件:DOMMouseScroll      必须用addEventListener绑定
  • 方向:ev.detail      上:-3      下:3
var box = document.getElementById('box');

var h = box.clientHeight;
function fn(ev) {
    var ev = ev || event;
    if (wheelDelta(ev) > 0) {
        h--;
    } else {
        h++;
    };
    box.style.height = h + 'px';
}

bind(box, 'mousewheel', fn);
bind(box, 'DOMMouseScroll', fn);


// 滚轮方向的兼容:上:120   下:-120
function wheelDelta(ev) {
    if (ev.wheelDelta) {
        return ev.wheelDelta;
    } else {
        return -40 * ev.detail;
    }
}

// 事件绑定封装
function bind(ele, event, callback) {
    if (ele.addEventListener) {
        // IE9及以上
        ele.addEventListener(event, callback, false);
    } else {
        // IE8及以下
        ele.attachEvent('on' + event, callback);
    }
}
原文地址:https://www.cnblogs.com/miaochaofan/p/14736797.html