• 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);
        }
    }
  • 相关阅读:
    (六)静态域,静态方法和静态代码块
    (五)final修饰符
    (四)函数的参数传递——值传递
    (三)java字符串
    第二章 shell的语法
    字符串操作
    PropertyGrid—属性类别排序
    PropertyGrid—为复杂属性提供下拉式编辑框和弹出式编辑框
    PropertyGrid--为复杂属性提供编辑功能
    PropertyGrid—添加EventTab
  • 原文地址:https://www.cnblogs.com/miaochaofan/p/14736797.html
Copyright © 2020-2023  润新知