JavaScript DOM 事件进阶

Posted YuLong~W

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript DOM 事件进阶相关的知识,希望对你有一定的参考价值。

事件

事件注册

传统方式

dom对象.事件名=事件处理程序

唯一性:同一个对象的同一个事件只能注册一个处理程序,后面注册的程序会将前面注册的程序覆盖掉

事件监听方式

由于不同浏览器采用的事件流实现方式不同,事件监听的实现存在兼容性问题。通常根据浏览器的内核,可以把浏览器划分为两大类

① 标准浏览器(W3C)

eventTarget.addEventListener(type, callback, [capture])

  • type:dom对象绑定的事件类型,如click、change、focus 不带on
  • callback:事件的处理程序
  • [capture]:可选参数,指定事件处理方式。默认为false,表示冒泡阶段完成事件处理,true为捕获阶段完成事件处理(事件流中详讲)

② 早期IE内核浏览器(如IE 6~IE 8)

eventTarget.attachEvent(type, callback)

  • type:onclick、onfocus 要带on
  • callback同上:

不唯一性:给同一个DOM对象的同一个事件添加多个事件处理程序

注册事件兼容性解决代码:

function addEventListener(element, eventName, fn) {
      // 判断当前浏览器是否支持 addEventListener 方法
      if (element.addEventListener) {
        element.addEventListener(eventName, fn);  // 第三个参数 默认是false
      } else if (element.attachEvent) {
        element.attachEvent('on' + eventName, fn);
      } else {
        // 相当于 element.onclick = fn;
        element['on' + eventName] = fn;
 } 

事件删除

  • 传统:eventTarget.οnclick=null
  • 早期:eventTarget.detachEvent(type,callback)
  • 标准:eventTarget.removeEventListener(type,callback)

删除事件兼容性解决代码:

 function removeEventListener(element, eventName, fn) {
      // 判断当前浏览器是否支持 removeEventListener 方法
      if (element.removeEventListener) {
        element.removeEventListener(eventName, fn);  // 第三个参数 默认是false
      } else if (element.detachEvent) {
        element.detachEvent('on' + eventName, fn);
      } else {
        element['on' + eventName] = null;
 } 

DOM事件流

事件流:指当事件发生时,会在发生事件的元素节点DOM树根节点之间按照特定的顺序进行传播,这个过程称之为事件流

  • 网景公司:采用事件捕获方式
  • 微软公司:采用事件冒泡方式
  • W3C:先捕获(但不处理),后冒泡(逐级处理)

事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程

事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程

在这里插入图片描述

  • JS 代码中只能执行捕获或者冒泡其中的一个阶段
  • onclick 和 attachEvent 只能得到冒泡阶段
  • addEventListener(type, callback, [capture]) 第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序
  • 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave

事件对象

事件对象的使用

事件对象:event

当事件发生后,由系统自动生成,跟事件相关一系列信息数据的集合存放在event对象中,不需传递参数

  • 早期IE内核浏览器:var 事件对象 = window.event
  • W3C内核浏览器:dom对象.事件 =function (event) { }

事件对象的兼容性解决:

e=e||window.event;

常用属性和方法

在这里插入图片描述

e.target和this区别

  • e.target返回的是触发事件的对象
  • this返回的是绑定事件的对象

了解: this有个类似写法:e.currentTarget (兼容性不常用)

<ul>
    <li></li>
    <li></li>
    <li></li>
</ul>
<script>
    var ul=document.querySelector('ul');
    ul.addEventListener('click',function(e){
        console.log(this); //返回ul对象
        console.log(e.target); //返回li对象
    });
</script>

在这里插入图片描述

e.target支持IE9以上,处理兼容性问题:

div.onclick = function(e) {
  e = e || window.event;
  var target = e.target || e.srcElement;
  console.log(target);
}

阻止默认行为

利用事件对象的preventDefault()方法和returnValue属性,禁止所有浏览器执行元素的默认行为

注意: 只有事件对象的cancelable属性设置为true,才可以使用preventDefault()方法取消其默认行为

阻止默认行为案例:
注册click事件,阻止a标签默认事件

<a href="http://www.baidu.com">百度</a>
<script>
    var a = document.querySelector('a')
    //标准浏览器
    a.addEventListener('click', function (e) {
        e.preventDefault()
    })
    a.onclick = function (e) {
    	//普通浏览器
        e.preventDefault()
        //低版本浏览器
        e.returnValue
    }
</script>

阻止事件冒泡

利用事件对象调用stopPropagation()方法和设置cancelBubble属性,实现禁止所有浏览器的事件冒泡行为

  • 标准浏览器:e.stopPropagation()
  • 非标准浏览器: e.cancelBubble = true

兼容性解决代码:

if(e && e.stopPropagation){
     e.stopPropagation();
}else{
    window.event.cancelBubble = true;
}

事件委托

原理: 不给子元素注册事件,而是给父元素注册事件监听器,利用 冒泡原理 影响到每个子元素

优点: 事件处理代码在父元素的事件执行。只操作了一次dom,提高了程序的性能

事件委托案例:

思路:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器

<ul>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
</ul>
<script>
    var ul = document.querySelector('ul')
    ul.addEventListener('click', function (e) {
        e.target.style.backgroundColor = 'pink'
    })
</script>

鼠标事件

在这里插入图片描述
1、禁止鼠标右击菜单:contextmenu

document.addEventListener('contextmenu', function (e) {
  e.preventDefault();
})

2、禁止鼠标选中:selectstart

document.addEventListener('selectstart', function (e) {
  e.preventDefault();
})

鼠标事件对象

MouseEvent:和鼠标事件相关的一系列信息集合,用来获取当前鼠标的位置信息
在这里插入图片描述
IE 6~IE 8浏览器中不兼容pageX和pageY属性,在项目开发时需要对IE 6~IE 8浏览器进行兼容处理

var pageX = event.pageX || event.clientX + 
(document.body.scrollLeft || document.documentElement.scrollLeft)
var pageY = event.pageY || event.clientY + 
(document.body.scrollTop || document.documentElement.scrollTop)

鼠标事件案例:图片跟随鼠标移动

<style>
    img{
        width: 200px;
        height: 180px;
        position: absolute;
        top: 2px;
    }
</style>
<body>
    <img src="./0.jpg" alt="">
    <script>
        var pic = document.querySelector('img')
        document.addEventListener('mousemove', function (e) {
            var x = e.clientX
            var y = e.clientY
            //确保鼠标位于图片最中间 都减去图片长宽一半
            //加单位px
            pic.style.left = x -100+ 'px'
            pic.style.top = y -90+ 'px'
            console.log('(x:' + x + ',y:' + y + ')')
        })
    </script>
</body>

在这里插入图片描述

键盘事件

在这里插入图片描述

注意:

  • 如果使用addEventListener 不需要加 on ,而普通注册事件需要加on
  • keypress和前面2个的区别是,它不识别功能键,比如左右箭头,shift 。ctrl等
  • 三个事件的执行顺序是:keydown — keypress — keyup

三者的区别:

  • keypress事件保存的按键值是ASCII码
  • keydown和keyup事件保存的按键值是虚拟键码
  • keydown和keypress如果按住不放的话,会重复触发该对应事件
  • keyup和keydown事件不区分字母大小写,keypress区分字母大小写

键盘事件对象

KeyBoardEvent对象:是跟键盘事件相关的一系列信息的集合

keyCode属性:可以得到相应的ASCII码值,进而判断用户按下了哪个键

ASCII表:
在这里插入图片描述

键盘事件案例:输出用户按下的键

<body>
    搜索: <input type="text">
    
    <script>
        var search = document.querySelector('input')
        document.addEventListener('keyup', function (e) {
            if (e.keyCode === 83) {
                search.focus()
            }
            var n = String.fromCharCode(e.keyCode)
            alert('你按了' + n + '键')
        })
    </script>
</body>

在这里插入图片描述

综合案例:快递单号放大显示

实现功能:input输入框内容同步显示到上方的方框中 并且失去焦点消失,获得焦点则出现
在这里插入图片描述

<style>
    * {
        margin: 0;
        padding: 0;
    }

    .search {
        position: relative;
        width: 178px;
        margin: 100px;
    }

    .con {
        display: none;
        position: absolute;
        top: -40px;
        width: 171px;
        border: 1px solid rgba(0, 0, 0, .2);
        box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
        padding: 5px 0;
        font-size: 18px;
        line-height: 20px;
        color: #333;
    }

    .con::before {
        content: '';
        width: 0;
        height: 0;
        position: absolute;
        top: 28px;
        left: 18px;
        border: 8px solid #000;
        border-style: solid dashed dashed;
        border-color: #fff transparent transparent;
    }
</style>
<body>
    <div class="search">
        <div class="con">123</div>
        <input type="text" placeholder="请输入您的快递单号" class="jd">
    </div>
    <script>
        var con=document.querySelector('.con');
        var input=document.querySelector('.jd');
        //注册keyup事件 不能用keydown和keypress
        input.addEventListener('keyup',function(){
            if(this.value==''){
                con.style.display='none';
            }else{
                con.style.display='block';
                con.innerText=this.value;
            }
        });
        //失去焦点
        input.addEventListener('blur',function(){
            con.style.display='none';
        })
        //获得焦点
        input.addEventListener('focus',function(){
            if(this.value!==''){
                con.style.display='block';
            }
        });
    </script>
</body>

以上是关于JavaScript DOM 事件进阶的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript DOM 事件进阶

JavaScript之DOM(下)

JavaScript-事件进阶

更改页面javascript代码(TamperMonkey)以将键盘笔触发送到父DOM

JavaScript进阶:如何写出优雅的JavaScript代码

进阶学习5:JavaScript异步编程——同步模式异步模式调用栈工作线程消息队列事件循环回调函数