JQuery 基础(3)—— DOM事件

一、JS中的DOM事件模型

JS中有两种事件模型:

  • DOM 0级事件模型 (几乎所有浏览器都支持)
  • DOm 2级事件模型(现代浏览器几乎都支持,IE8之前的不支持)

(一)DOM 0级事件模型

有两种形式:

//第一种:html标签中添加事件
<input type="button" onclick="doSomething(...)"/>
//第二种:dom对象绑定事件
input.onclick=function(){...}

缺点:只能添加一个相同的事件,之后添加的会覆盖前面的。

input.onclick=function(){alert(1);} //被覆盖了,不会执行
input.onclick=function(){alert(2);} //之后的dom点击事件会覆盖前面的。


(二)事件冒泡

点击子元素,其父元素的事件处理模型也都被执行了。

//点击<p>标签
<body>
    <div id="div1">
        <div id="div1-1">
            <div id="div1-1-1">
                <div id="div1-1-1-1">
                    <p id="p1">
                        事件冒泡测试
                    </p>
                </div>
            </div>
        </div>
    </div>
    <script type="text/javascript">
        document.getElementById('p1').onclick=function(event){console.log('p1');};
        document.getElementById('div1').onclick=function(event){console.log('div1');};
        document.getElementById('div1-1').onclick=function(event){console.log('div1-1');};
        document.getElementById('div1-1-1').onclick=function(event){console.log('div1-1-1');};
        document.getElementById('div1-1-1-1').onclick=function(event){console.log('div1-1-1-1');};
        //结果为从内到外以此触发事件,vue中也会遇到
    //p1
    //div1-1-1-1
    //div1-1-1
    //div1-1
    //div1
    </script>

</body>

取消事件冒泡

  • event.stopPropagation();
  • event.cancelBubble = true;


(三)DOM 2级事件模型

DOM 2级事件模型弥补了DOM 0级事件缺陷,可以绑定多个相同事件。
同时也拥有事件捕获事件冒泡的功能(事件捕获:从祖先元素捕获到子元素,和冒泡相反)
事件捕获:从祖先元素向下传播
事假冒泡:从子元素向上传播

DOM2注册事件处理函数:
addEventListenter(eventType,listener,useCapture)

  • eventType:事件类型(click、focus、blur)不带on
  • listener:事件处理函数,可以是匿名函数
  • useCapture:默认值是false,只冒泡不捕获;true只捕获不冒泡(捕获很少用)。

attachEvent(eventName,handler)(IE)
老的IE浏览器使用attachEvent添加事件处理函数

  • eventName:事件名称(需要加上on)
  • handler:事件处理函数

var event = event || window.event;
var target = event.target || event.srcElement;

使用原生JS绑定DOM事件需要兼容各种浏览器的写法

var EventsUtility = {
    addEvent: function (element, type, callback) {
        if (typeof addEventListener !== 'undefined') { //DOM 2级事件
            element.addEventListener(type, callback, false);
        } else if (typeof attachEvent !== 'undefined') {
            element.attachEvent('on' + type, callback); //DOM 2级事件,兼容IE
        } else {    //DOM 0级事件,兼容低版本浏览器
            element['on' + type] = callback;
        }
    },

    removeEvent: function (element, type, callback) {
        if (typeof removeEventListener !== 'undefined') {   //DOM 2级事件
            element.removeEventListener(type, callback, false);
        } else if (typeof detachEvent !== 'undefined') {
            element.detachEvent('on' + type, callback); //DOM 2级事件,兼容IE
        } else {    //DOM 0级事件,兼容低版本浏览器
            element['on' + type] = null;
        }
    },
}


二、jQuery事件模型

特点:

  • 提供统一的事件处理方法
  • 内部采用了DOM2级事件模型,允许添加多个事件处理函数
  • 使用标准事件名称,不带on
  • event事件实例作为事件处理函数的第一个参数
  • 标准化了事件常用属性,解决了兼容性问题 比如target
  • 提供了统一的事件取消和阻止默认行为的方法

(一)添加DOM事件处理

.on(eventType[,selector][,data][,handler]) //推荐使用,其他的方法不推荐
$('XXX').on(eventType[,select][,data],function(event){
    //event.target得到的是事件发生元素
})
  • eventType 事件类型,多个事件可以用空格分隔
  • selector表示一个选择器 指定事件注册的后代(用于事件委托)
  • data 表示传递的数据,可以在函数中使用,通过event.data获取
  • 表示事件处理函数
  • 可以使用链式语法添加多个事件

事件委托

如果要为大量的元素绑定事件的话,为每个元素都绑定一个事件效率会很低。使用事件委托可以提高效率。
事件委托,利用事件冒泡的原理,把子元素的相同的事件委托给父元素,子元素上发生的某个事件会从父元素哪里得到具体的事件处理程序。

  • 此时event.target是发生事件的子元素
  • 上面的selector可以指定哪些子元素需要委托此事件
  • 新添加的符合selector的子元素默认就委托了此事件
//新闻列表数量太多,每一个都绑定事件效率低,而且还会有新加
<body>
    <div class="new">
        <p class="new-li p1">新闻段落1</p>
        <p class="new-li p2">新闻段落2</p>
        <p class="new-li p3">新闻段落3</p>
        <p class="new-li p4">新闻段落4</p>
        <p class="new-li p5">新闻段落5</p>
        <p class="new-li p6">新闻段落6</p>
        <p class="new-li p7">新闻段落7</p>
        <p class="new-li p8">新闻段落8</p>
        <p class="new-li p9">新闻段落9</p>
        <p class="new-li p10">新闻段落10</p>
        <div class="new-li-page">事件
            这是分页,不会触发
        </div>
    </div>
    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script type="text/javascript">
        $(function(){  
            //为父元素绑定事件处理,利用事件委托,将指定子元触发的事件委托给父元素处理
            $('.new').on('click','p',{title: '新闻标题'},function(event){
                console.log($(event.target).text());
            });
        });
    </script>
</body>


统一方法和属性

  • 事件冒泡:stopPropagation()
  • 阻止默认行为:preventDefault()
  • 同时阻止冒泡和默认行为:return false

所有支持的事件

事件名 说明 事件名 说明
blur focusout
change keydown
click keypress
dblclick keyup
error load
focus unload
focusin
mousedown mouseup
mouseenter ready
mouseleave resize
mousemove scroll
mouseout select
mouseover submit


一次性的事件处理

one(eventType[,selector][,data],handler)
这个方法注册的事件执行一次后就被销毁了。

jQuery不支持双击事件!jQuery不支持双击事件!!jQuery不支持双击事件!!!


(二)移除DOM事件处理

off(eventType[,selector][,handler])

  • eventType:事件类型,可以使用空格分开的多个类型
  • selector:事件目标
  • handler:事件处理函数,和removeEventListener()一样,必须是不带括号的函数名,如果没有参数,则删除所有类型的事件处理

1.删除一个事件处理

<script src="//cdn.bootcss.com/jquery/1.12.4/jquery.js"></script>
<script>
$(function () {
    var click1 = function(event){
         $(event.target).css('text-indent','1px');
    }
    var click2 = function(event){
        console.log($(event.target).text());
    }
    var click3 = function(event){
        console.log('clicked');
    }
    var mouseover1 = function(){
        console.log('mouseover');
    }

    $('div.cards').on('click','div',click1)
    .on('click','div',click2)
    .on('click','div',click3);

    $('div.cards').off('click','div',click1); //移除click1点击事件
});
</script>

2.移除同类型事件处理

<script>
    $(function () {
        var click1 = function(event){
             $(event.target).css('text-indent','1px');
        }
        var click2 = function(event){
            console.log($(event.target).text());
        }
        var click3 = function(event){
            console.log('clicked');
        }
        var mouseover1 = function(){
            console.log('mouseover');
        }

        $('div.cards').on('click','div',click1)
        .on('click','div',click2)
        .on('click','div',click3)
        .on('mouseover','div',mouseover1);

        $('div.cards').off('click'); //移除所有click点击事件
    });
</script>

3.移除多个类型的事件

<script>
$(function () {
    var click1 = function(event){
         $(event.target).css('text-indent','1px');
    }
    var click2 = function(event){
        console.log($(event.target).text());
    }
    var click3 = function(event){
        console.log('clicked');
    }
    var mouseover1 = function(){
        console.log('mouseover');
    }

    $('div.cards').on('click','div',click1)
    .on('click','div',click2)
    .on('click','div',click3)
    .on('mouseover','div',mouseover1);

    $('div.cards').off('click mouseover'); //移除多个事件处理
});
</script>

4.移除元素上所有事件

<script>
$(function () {
    var click1 = function(event){
         $(event.target).css('text-indent','1px');
    }
    var click2 = function(event){
        console.log($(event.target).text());
    }
    var click3 = function(event){
        console.log('clicked');
    }
    var mouseover1 = function(){
        console.log('mouseover');
    }

    $('div.cards').on('click','div',click1)
    .on('click','div',click2)
    .on('click','div',click3)
    .on('mouseover','div',mouseover1);

    $('div.cards').off(); //移除多个事件处理
});
</script>


(三)事件实例对象的属性方法

1.事件实例对象的属性

属性名 说明 属性名 说明
altkey data
bubbles detail
button delegateTarget
cancelable eventPhase
charCode metaKey
clientX namesoace
clientY offsetX
ctrlKey offsetY
currentTarget
originalTarget screenX、screenY
originalEvent shiftKey
pageX target
pageY timeStamp
prevValue type
relatedTarget view
result which

PS:标红的表示浏览器兼容性有问题,并且JQuery对这个有兼容性问题的属性做了兼容性处理

2.事件实例对象的方法

  • preventDefault() 通知浏览器不要执行与事件关联的默认动作(例如:点击按钮表单提交,点击超链接页面跳转等)
  • stopPropagation() 阻止当前事件在DOM树上冒泡。
  • stopImmediatePropagation() 阻止事件冒泡,并阻止之后绑定于本元素上其他事件的执行。(意思就是只执行第一个绑定的事件)
  • isDefaultPrevented()检测是否调用了preventDefault()方法
  • isPropagationStopped()检测是否调用了stopPropagation()方法
  • isImmediatePropagationStopped()检测是否调用了stopImmediatePropagation()方法

(1)stopPropagation()

<div id="div1">
    <div id="div1-1">
        <div id="div1-1-1">
            <div id="div1-1-1-1">
                <div id="p1">
                    事件冒泡测试
                </div>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript" src="//cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script type="text/javascript">
    $(function(){
        $('div').on('click',function(event){
            event.stopPropagation();
                console.log('clicked %o',$(this)); //结果只会在控制台中打印出<div id="p1">元素的jQuery对象
        });
    });
</script>


(2)stopImmediatePropagation()

//使用上面的例子
<script type="text/javascript">
    $(function(){
        $('div').on('click',function(event){
            event.stopPropagation();
                console.log('clicked %o',$(this)); //只是阻止了事件冒泡,后面绑定的事件正常执行
        }).on('click',function(){
            console.log('clicked');
        });
    });
</script>

//使用stopImmediatePropagation()
<script type="text/javascript">
    $(function(){
        $('div').on('click',function(event){
            event.stopImmediatePropagation();
                console.log('clicked %o',$(this)); 
        }).on('click',function(){
            console.log('clicked'); //不仅阻止了冒泡,,后面绑定的事件也阻止了
        });
    });
</script>


(四)触发事件(使用代码触发)

  • trigger(eventType[,data])效果与真实触发类似,有冒泡,所有匹配元素都会触发。
  • triggerHandler(eventType[,data])

triggerHandler()与trigger()的区别

  • 不会触发浏览器默认事件
  • 不会产生事件冒泡
  • 只会触发jQuery对象集合中第一个元素的事件处理函数
    返回事件处理函数的返回值,而不是jQuery对象。
    无法直接使用链式语法

(五)快捷方法添加事件

在(一)中我们使用.on(eventType[,seletor][,data][,hander])这个方法添加DOM事件
jQuery还提供了更便捷的添加事件的方法

使用方法

  • eventName([data,]handler) 快捷的注册事件的方法
  • eventName() 快捷的触发事件的方法
eventName eventName
blur() keydown()
change() keypress()
click() keyup()
dblclick()
error()
focus()
focusin()
focusout()
mousedown() read()
mouseenter() resize()
mouseleave() scroll()
mousemove() select()
mouseout() submit()
mouseover() unload()
mouseup()

hover方法(重要)

hover()是jQuery专门设置的一个方法。
hover()方法相当于同时调用了mouseenter()和mouseleave()方法,可以避免鼠标进入子元素触发父元素mouseout事件的现象
而mouseenter()和mouseleave()弥补了mouseover()和mouseout()的不足。

  • hover(enterHandler,leaveHandler)
  • hover(handler)


(六)自定义事件

自定义事件不是真正意义上的事件,可以把它理解为自定义函数,触发自定义事件就相当于调用自定义函数。
使用的是on()方法
参数eventType就是自定义的事件名称
通过其他内置事件执行trigger()方法来触发自定义事件


(七)事件命名空间

  • eventName.namespace
    使用命名空间,可以区分同类型的事件方法,触发指定的事件方法,而不会触发所有同类型的事件方法
<body>
    <ul>
        <li class="item1">新闻标题-1</li>
        <li class="item2">新闻标题-2</li>
        <li class="item3">新闻标题-3</li>
        <li class="item4">新闻标题-4</li>
        <li class="item5">新闻标题-5</li>
        <li class="item6">新闻标题-6</li>
        <li class="item7">新闻标题-7</li>
        <li class="item8">新闻标题-8</li>
        <li class="item9">新闻标题-9</li>
    </ul>
    <button id="even">点击偶数</button>
    <button id="odd">点击奇数</button>
    <button id="all">全部点击</button>
    <script src="../../../vendor/jquery-1.12.4.js"></script>
    <script>
    $(function() {

        $('li:odd').on('click.even', function(e) { //这里就是定义了事件命名空间eventName.namespace,
            console.log('%o 偶数', $(this));
        });
        $('li:even').on('click.odd', function(e) {
            console.log('%o 奇数', $(this));
        });
        $('li').eq(0).on('click.even.0', function(e) {
            console.log('%o 0', $(this));
        });
        $('#even').click(function() {
            //使用trigger可以触发on中事件
            $('li').trigger('click.even'); //这里使用了事件命名空间,
        });
        $('#odd').click(function() {
            $('li').trigger('click.odd');
        });
        $('li').off('.even');

    });
    </script>
</body>

(八)综合案例

使用自定义事件和事件委托实现标签页的切换

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>标签页的切换</title>
    <style>
        *{margin: 0;padding: 0;}
        li{list-style-type: none;}
        .main{
            width: 70%;
            margin: 0 auto;
        }
        /*标签页*/
        .main .tab{
            width: 100%;
            margin: 100px 0;
        }
        .tab .tab-nav{
            width: 100%;
            height: 50px;

        }
        .tab .tab-nav ul{
            height: 48px;
            border-bottom: 2px solid #0066ff;
            padding: 0 80px;    
        }
        .tab .tab-nav .nav-li{
            width: 100px;
            height: 46px;
            line-height: 46px;
            text-align: center;
            float: left;
            color: #FFFFFF;
            border: 2px solid #0066FF; /*li的盒子的高度为54px,底部边框会和.tab-content的顶部边框重合*/
            border-radius: 12px 12px 0 0;
            background-color: #0066FF;
            margin: 0 2px;
            cursor: pointer;
        }
        .tab .tab-nav .active{
            border-bottom-color: #FFFFFF;
            background-color: #FFFFFF;
            color: #000000;
        }
        .tab .tab-content{
            width: auto;
            height: 450px;
            border:2px solid #0066FF;
            border-top:0px;
            position: relative;
        }
        .tab .tab-content .tab-item{
            width: 100%;
            height: 450px;
            position: absolute;
            display: none;
        }
        .tab .tab-content .active{
            display: block;
        }
        /*/标签页*/
    </style>
</head>

<body>
    <div class="main">
        <!-- tab标签页 -->
        <div class="tab" id="tab">
            <!-- 标签页导航 -->
            <div class="tab-nav">
                <ul>
                    <li class="nav-li active">HTML</li>
                    <li class="nav-li">JS</li>
                    <li class="nav-li">CSS</li>
                    <li class="nav-li">jQuery</li>
                </ul>
            </div>
            <!-- /标签页导航 -->
            <!-- 标签页内容 -->
            <div class="tab-content">
                <div class="tab-item active"><h1>HTML</h1></div>
                <div class="tab-item"><h1>JS!</h1></div>
                <div class="tab-item"><h1>CSS!!</h1></div>
                <div class="tab-item"><h1>jQuery!!!</h1></div>
            </div>
            <!-- /标签页内容 -->
        </div>
        <!-- /tab标签页 -->
    </div>

    <script src="//cdn.bootcss.com/jquery/1.12.4/jquery.js"></script>
    <script type="text/javascript">
        $(function(){
            //给标签页绑定事件
            $('#tab').on('switchTab','li',function(event,liObj,liIndex){   //自定义事件
                //导航切换
                liObj.siblings('li').removeClass('active').end().addClass('active'); 
                //内容项切换
                $('#tab div.tab-item').removeClass('active').eq(liIndex).addClass('active');
            }).click(function(event){
                 $(event.target).trigger('switchTab',[$(event.target),$(event.target).index()]);    //触发自定义事假
            });
        });
    </script>
</body>

</html>

猜你喜欢

转载自blog.csdn.net/weixin_39141044/article/details/80354168