jQuery——事件

JavaScript和HTML之间的交互是通过用户和浏览器操作页面时引发的事件来处理的。 jQuery增加并扩展了基本的事件处理机制。jQuery不仅提供了更加优雅的事件处理语法,而且极大的增强了事件处理能力。


加载DOM

浏览器加载文档完毕后,浏览器会通过JS为DOM元素添加事件。在常规的JavaScript代码中,通常使用window.onload方法,而在jQuery中,使用的$(document).ready()方法。 $(document).ready()是事件模块中最重要的一个函数,可以极大的提高Web应用程序的响应速度。jQuery就是用 $(document).ready()方法来代替传统JavaScript的window.onload方法的,通过使用该方法,可以在DOM载入就绪时就对其进行操纵并调用执行它所绑定的函数。在使用过程中,需要注意 $(document).ready()方法和window.onload方法之间的细微差别。

1. 执行时机
$(document).ready()方法和window.onload方法有相似的功能,但是在执行时机方面是有区别的,window.onload方法才是在网页中所有元素(包括元素的所有关联文件)完全加载到浏览器后才执行,JS此时才可以访问网页中的任何元素。而通过jQuery中的$(document).ready()方法注册的事件处理程序,在DOM完全就绪时就可以被调用。此时,网页的所有元素对jQuery而言都是可以访问的,但是,这并不意味着这些元素关联的文件都已经下载完毕

举一个例子,有一个大型图库网站,为网页中所有图片添加某些行为,例如单击图片后让它隐藏或显示。如果使用window.onload方法来处理,那么用户必须等到每一幅图片都加载完毕后,才可以进行操作。如果使用jQuery的$(document).ready()方法进行设置,只要DOM就绪就可以操作了。不需要等待图片下载完毕。

另外,需要注意一点,在$(document).ready()方法内注册的事件,只要DOM就绪就会被执行,因此可能此时元素的关联文件未下载完,例如与图片有关的HTML下载完毕,并且已经解析为DOM树了,但很有可能图片还未加载完毕,所以例如图片的高度和宽度这样的属性此时不一定有效。要解决这个问题,可以使用jQuery中另一个关于页面加载的方法——load()。load()方法会在元素的onload事件中绑定一个处理函数,如果处理函数绑定给window对象,则会在所有内容(包括窗口,框架,对象和图像等)加载完毕后触发,如果处理函数绑定在元素上,则会在元素的内容加载完毕后触发。

    $(window).load(function() {
        // ...
    });

    // 等价于

    window.onload = function() {
        // ....
    };

2. 多次使用
windows.onload()和$(document).ready()的区别

现在有两个函数:

        alert("one");
    }
    function two() {
        alert("two");
    }

当网页加载完毕后,通过如下的JavaScript代码来分别调用one函数和two函数。

    window.onload = one;
    window.onload = two;

然而运行后,发现只弹出two对话框。

字符串"one"对话框不能被弹出的原因是:JavaScript的onload事件一次只保存对一个函数的引用,它会自动用后面的函数覆盖前面的函数,因此不能在现有的行为上添加新的行为。

为了达到两个函数顺序触发的效果,只能再创建一个新的JavaScript方法来实现。

    window.onload = function() {
        one();
        two();
    }

虽然这样编写代码能解决某些问题,但还是不能满足某些需求,例如有多个JavaScript文件,每个文件都有用到window.onload方法,这种情况用上面提到的方法编写代码会非常麻烦。而jQuery的$(document).ready()方法能够很好的处理这些情况,每次调用$(document).ready()方法都会在现有的行为上追加新的行为,这些行为函数会根据注册的顺序依次执行。例如如下的jQuery代码;

    $(document).ready(function() {
        one();
    })
    $(document).ready(function() {
        two();
    })

3. 简写方式

    $(document).ready(function() {

    })

    // 简写方式

    $(function() {
        
    })

另外,$(document)也可以简写$(),当$()不带参数时,默认参数就是document。

    $().ready(function() {

    });

jQuery——事件绑定

在文件装载完成之后,如果打算为元素绑定事件来完成某些操作,则可以使用bind()方法来对匹配元素进行特定事件的绑定,bind()方法的调用格式为:

$(selector).bind(event,data,function)

第1个参数是事件类型,类型包括:blur,focus,load,resize,scroll,unload,click,dbclick,mousedown,mouseup,mousemove,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup和error等。当然也可以自定义名称。

第2个参数为可选参数,作为event.data属性值传递给事件对象的额外数据对象。

第3个参数则是用来绑定的处理函数。

注意:可以发现,jQuery中的事件绑定类型比普通的JavaScript事件绑定类型少了on

1. 基本效果
假设网页中有一个FAQ,单击标题链接将显示内容。
HTML:

    <div id="panel">
        <h5 class="head">什么是jQuery</h5>
        <div class="content">
            jQuery是............................................................
            ....................................................................
            程序员的设计思路和编写程序的方式。
        </div>
    </div>

设置CSS后如图。


现在需求如下:

  1. 等待DOM加载完毕
  2. 找到标题所在的元素,绑定click事件
  3. 找到内容元素,将内容元素显示

很容易就能写出:

    $(function() {
        $("#panel h5.head").bind("click",function() {
            $(this).next().show();      // $(this).next() 获取class => .content
        })
    })

运行代码,单击”内容”链接,“内容”就展开了。

与ready()方法一样,bind()方法也可以多次调用。

this引用的是携带相应行为的DOM元素,为了使该DOM元素能够使用jQuery中的方法,可以使用$(this)将其转换为jQuery对象。

2. 加强效果
需求:
第二次单击“标题”,“内容”隐藏;再次单击“标题”,“内容”又显示,两个动作循环出现。

    $(function() {
        $("#panel h5.head").bind("click",function() {
            if ($(this).next().is(":visible")) {
                $(this).next().hide();
            } else {
                $(this).next().show();
            }
        })
    })

代码中,发现$(this).next()多次使用,因此可以为它定义一个局部变量。

    var $content = $(this).next();

然后把局部变量引入到代码中,改进后的jQuery代码如下:

    $(function() {
        $("#panel h5.head").bind("click",function() {
            var $content = $(this).next();
            if ($content.is(":visible")) {
                $content.hide();
            } else {
                $content.show();
            }
        })
    })

优化建议:当发现相同的选择器在代码中多次出现,请用变量把它缓存起来

3. 改变绑定事件的类型

上面例子中给元素绑定的是事件类型是click,当用户单击的时候会触发绑定的事件,然后执行事件的函数代码。现在把事件类型换成mouseover和mouseout,即光标滑过时,就会触发事件。

    $(function() {
        $("#panel h5.head").bind("mouseover",function() {
            $(this).next().show();
        }).bind("mouseout",function() {
            $(this).next().hide();
        })
    })

4. 简写绑定事件

像click、mouseover、mouseout这类事件,在程序中经常会用到,jQuery为此提供一套简写的方法。简写方法和bind()方法的使用类似,实现效果相同,唯一的区别是能够减少代码量。

    $(function() {
        $("#panel h5.head").mouseover(function() {
            $(this).next().show();
        }).mouseout(function() {
            $(this).next().hide();
        })
    })

合成事件

jQuery中有两个合成事件,hover()和toggle()。

1. hover()
语法结构为:

    hover(enter,leave);

hover()用于模拟光标悬停事件。当光标移动到元素上时,会触发指定的第一个函数(enter);当光标移除这个元素时,触发指定第二个函数(leave)。

所以可以:

    $(function() {
        $("#panel h5.head").hover(function() {
            $(this).next().show();
        },function() {
            $(this).next().hide();
        })
    })

注意:

  • CSS中有伪类选择符,如:hover,当用户光标悬停在元素上时,会改变元素的外观。
  • hover()方法准确来说是替代jQuery中的bind("mouseenter")和bind("mouseleave"),而不是替代bind("mouseover")和bind("mouseout")。

2. toggle()
语法结构为:

    toggle(fn1,fn2,...fnN);

toggle()用于模拟鼠标连续单击事件。第1次单击元素,会触发第1个函数fn1;当再次单击同一元素时,则触发指定的第2个函数fn2;如果有更多函数,则依次触发,直到最后一个。随后的每次单击都重复对这几个函数的轮番调用。

    $(function() {
        $("#panel h5.head").bind("click",function() {
            if ($(this).next().is(":visible")) {
                $(this).next().hide();
            } else {
                $(this).next().show();
            }
        })
    })

3. 再次加强效果
为了有更好的用户体验,现在需要在用户单击“标题”链接后,不仅显示“内容”,而且高亮显示“标题”。
首先定义一个CSS样式:

    .highlight {
        background: #ff3300;
    }
    $(function() {
        $("#panel h5.head").bind("click",function() {
            if ($(this).next().is(":visible")) {
                $(this).next().hide();
                $(this).removeClass("highlight");
            } else {
                $(this).next().show();
                $(this).addClass("highlight");
            }
        })
    })

事件冒泡

1. 什么是冒泡
在页面上可以有多个事件,也可以多个元素响应同一个事件。假设网页上有两个元素,其中一个元素嵌套在另一个元素内,并且都被绑定了click事件,同时body元素上也绑定了click事件:

<body>
    <div id="content">
        外层div元素
        <span>内层span元素</span>
        外层div元素
    </div>
    <div id="msg"></div>
</body>
    $(function() {
        $("span").bind("click",function() {
            var txt = $("#msg").html() + "<p>内层span元素被单击</p>";
            $("#msg").html(txt);
        });
        $("#content").bind("click",function() {
            var txt = $("#msg").html() + "<p>外层div元素被单击</p>";
            $("#msg").html(txt);
        })
        $("body").bind("click",function() {
            var txt = $("#msg").html() + "<p>body元素被单击</p>";
            $("#msg").html(txt);
        })
    })

当单击内部span元素的时候,即触发span元素的click事件时,会输出3条纪录,这就是由事件冒泡引起。

在单击span元素的同时,也单击了包含span元素的元素div和包含div元素的元素body,并且每一个元素都会按照特定的顺序响应click事件。

2. 事件冒泡引发的问题
事件冒泡可能会引起预料之外的效果。比如,本来只想触发span元素的click事件,然而div元素和body元素的click事件也同时被触发了,因此有必要对作用范围进行限制。

事件对象
由于IE-DOM和标准DOM的实现事件对象的方法各不相同,导致在不同浏览器中获取事件对象变得比较困难。针对这个问题,jQuery进行了必要的扩展和封装,从而使得在任何浏览器中都能轻松地获取事件对象以及事件对象的一些属性。

    $("element").bind("click",function(event) {
        // ...
    });

这样,当单击element元素时,事件对象就被创建了。这个事件对象只有事件处理函数才能访问到。事件处理函数执行完毕后,事件对象就被销毁。

停止事件冒泡
停止事件冒泡可以阻止事件中其他对象的事件处理程序被执行,在jQuery中提供了stopPropagation()来停止事件冒泡。

    $("span").bind("click",function(event) {
        var txt = $("#msg").html() + "<p>span元素被单击</p>";
        $("#msg").html(txt);
        event.stopPropagation();
    })

当单击span元素时,只会触发span元素上的click事件,而不会触发div元素和body元素的click事件。

阻止默认行为
网页中的元素都有自己的默认的行为,例如,单击超链接后会跳转、单击提交按钮后表单提交,有时需要阻止元素的默认行为。

在jQuery中,使用preventDefault()方法来阻止元素默认行为。

    event.stopPropagation();

事件捕获
事件捕获和事件冒泡是刚好相反的两个过程,事件捕获是从最顶端往下触发。

事件捕获是从最外层元素开始,然后再到最里层元素。因此绑定的click事件,首先会传递给body元素,然后到div,最后才到span元素。

遗憾的是,并非所有主流浏览器都支持事件捕获,并且这个缺陷无法通过JavaScript来修复,jQuery不支持事件捕获。如果需要用到,直接使用原生JavaScript。

事件对象的属性

event.type
该方法作用是可以获取到事件的类型。

    $("a").click(function(event) {
        alert(event.type);  // 获取事件类型
        return false;       // 阻止事件跳转
    })

event.preventDefault()
阻止默认的事件行为。JavaScript中符合W3C规范的preventDefault()方法在IE中无效,jQuery对其进行了封装,可以兼容各种浏览器。

event.target
event.target的作用是获取到触发事件的元素,jQuery对其封装后,避免了各个浏览器不同标准的差异。

    $("a[href='http://google.com']").click(function(event) {
        var tg = event.target;          // 获取事件对象
        alert(tg.href);
        return false                    // 阻止链接跳转
    })

以上代码会输出:

    "http://google.com"

event.relatedTarget
在标准DOM中,mouseover和mouseout所发生的元素可以通过event.target来访问,相关元素是通过event.relatedTarget来访问的。event.relatedTarget在mouseover中相当于IE浏览器的event.fromElement,在mouseout中相当于IE浏览器的event.toElement,jQuery对其进行了封装,使之兼容各种浏览器。

event.pageX and event.pageY
该方法的作用是获取到光标相对于页面的x坐标和y坐标。如果没有使用jQuery,那么IE浏览器中是用event.x/event.y,在Firefox中是用event.pageX/event.pageY。如果页面上有滚动条,则还要加上滚动条的宽度和高度。

    $("a").click(function(event) {
        alert("Current mouse position: "+event.pageX+", "+event.pageY);
        return false;
    })

event.which
该方法作用是在鼠标单击事件中获取到鼠标的左、中、右键;

    $("a").mousedown(function(e) {
        alert(e.which); // 1 = 鼠标左键 2 = 鼠标中键  3 = 鼠标右键
    })

移除事件

在绑定事件的过程中,不仅可以为同一个元素绑定多个事件,也可以为多个元素绑定同一个事件。假设网页上有一个button元素:

<body>
    <button id="btn">单击我</button>
    <div id="test"></div>
</body>
<script>

    $(function() {
        $("#btn").bind("click",function() {
            $("#test").append("<p>我的绑定函数1</p>");
        }).bind("click",function() {
            $("#test").append("<p>我的绑定函数2</p>");
        }).bind("click",function() {
            $("#test").append("<p>我的绑定函数3</p>");
        })
    })

</script>

1. 移除按钮元素上以前注册的事件
首先在网页上添加一个移除事件的按钮。

    <button id="delAll">删除所有事件</button>

最后:

    $("#delAll").click(function() {
        $("#btn").unbind("click");
    })

因为元素绑定的都是click事件,所以布鞋参数也可以达到同样目的。

    $("#delAll").click(function() {
        $("#btn").unbind();
    })

下面来看看unbind()方法的语法结构。

    unbind([type] , [data])

第1个参数是事件类型,第2个参数是将要移除的函数。

  1. 如果参数,则删除所有绑定的事件。
  2. 如果提供了事件类型作为参数,则只删除该类型的绑定事件。
  3. 如果把绑定时传递的处理函数作为第2个参数,则只有这个特定的事件处理函数会被删除。

2. 移除<button>元素的其中一个事件
首先需要为这些匿名处理函数指定一个变量。

    $(function() {
        $("#btn").bind("click",myFun1=function() {
            $("#test").append("<p>我的绑定函数1</p>");
        }).bind("click",myFun2 = function() {
            $("#test").append("<p>我的绑定函数2</p>")
        }).bind("click",myFun3 = function() {
            $("#test").append("<p>我的绑定函数3</p>")
        });
    });

    $("#delTwo").click(function() {
        $("#btn").unbind("click",myFun2);   // 删除绑定函数2
    })

另外,对于只需要触发一次,随后就要立即解除绑定的情况,jQuery提供了一种简写方法——one()方法。one()方法可以为元素绑定处理函数。当处理函数触发一次后,立即被删除。即在每个对象上,事件处理函数只会被执行一次。

one()和bind()方法类似,使用方法也与bind()方法相同。

    $(function() {
        $("#btn").one("click",function() {
            $("#test").append("<p>我的绑定函数1</p>");
        }).one("click",function() {
            $("#test").append("<p>我的绑定函数2</p>");            
        }).one("click",function() {
            $("#test").append("<p>我的绑定函数3</p>");
        });
    });

这里的三个click事件处理函数只会执行一次。


模拟操作

1. 常用模拟
以上的例子都是用户必须单击按钮,才能触发click事件,但是有时,需要通过模拟用户操作,来达到单击的效果,例如在用户进入页面后,就触发click事件,不需要用户主动单击。

在jQuery中,可以使用trigger()方法来完成模拟操作,例如:

    $("#btn").trigger("click");

为id为btn的按钮触发click事件。
这样,当页面装载完毕后,就会立刻输出想要的效果。
也可以直接用简化写法click()。

    $("#btn").click();
    $(function() {
        $("#btn").bind("click",function() {
            $("#test").append("<p>我的绑定函数1</p>");
        })

        $("#btn").trigger("click");
    })

运行后,不需要点击鼠标,就已经模拟了一次click事件。

2. 触发自定义事件
trigger()方法不仅能触发浏览器支持的具有相同的名称的事件,也可以触发自定义名称的事件。
例如为元素绑定一个myClick的事件,jQuery代码如下:

        $("#btn").bind("myClick",function() {
            $("#test").append("<p>我的自定义事件</p>");
        })

        $("#btn").trigger("myClick");

3. 传递数据
trigger(type,[data])方法有两个参数,第1个参数是要触发的事件类型,第2个是参数是要传递给事件处理函数的附加数据,以数组形式传递。通常可以通过传递一个参数给回调函数来区别这次事件是代码触发还是用户触发。

        $("#btn").bind("click",function(event,message1,message2) {
            $("#test").append("<p>" + message1 + message2 + "</p>");
        })

        $("#btn").trigger("myClick",["我的自定义","事件"]);     // 传递两个数据

运行代码如图:


4. 执行默认操作
trigger()方法触发事件后,会执行浏览器默认操作。如:

    $("input").trigger("focus");

以上代码不仅会触发为<input>元素绑定的focus事件,也会使<input>元素本身得到焦点(这是浏览器默认操作)

如果只想触发绑定的focus事件,而不想执行浏览器默认操作,可以使用jQuery中另一个类似的方法——triggerHandler()方法。

    $("input").triggerHandler("focus");

该方法会触发<input>元素上绑定的特定事件,同时取消浏览器对此事件的默认操作,即文本框值触发绑定的focus事件,不会得到焦点。

其他用法

1. 绑定多个事件类型
例如可以为事件一次性绑定多个事件类型。

        $("div").bind("mouseover mouseout",function() {
            $(this).toggleClass("over");
        })

当光标滑入<div>元素时,该元素的class切换为over;当光标滑出<div>元素时,class切换为先前的值。这段代码等同于:

        $("div").bind("mouseover",function() {
            $(this).toggleClass("over");
        }).bind("mouseout",function() {
            $(this).toggleClass("over");
        });

2. 添加事件命名空间,便于管理
例如可以把为元素绑定的多个事件类型用命名空间规范起来:

    $(function() {
        $("div").bind("click.plugin",function() {
            $("body").append("<p>click event</p>");
        });
        $("div").bind("mouseover.plugin",function() {
            $("body").append("<p>mouseover event</p>");
        });
        $("div").bind("dblclick",function() {
            $("body").append("<p>dblclick event</p>");
        });
        $("button").click(function() {
            $("div").unbind(".plugin");
        });
    });

在所绑定的事件类型后面添加命名空间,这样在删除事件时只需指定命名空间即可。单击<button>元素后,plugin的命名空间被删除,而不在plugin命名空间的dblclick事件依然存在。

    $(function() {
        $("div").bind("click.plugin",function() {
            $("body").append("<p>click event</p>");
        });
        $("div").bind("mouseover.plugin",function() {
            $("body").append("<p>mouseover event</p>");
        });
        $("div").bind("dblclick",function() {
            $("body").append("<p>dblclick event</p>");
        });
        $("button").click(function() {
            $("div").unbind(".plugin");
        });
    })

删除多个事件代码也可以写为链式调用。

    $("div").unbind("click").unbind("mouseover");

3. 相同事件名称,不同命名空间执行方法

例如可以为元素绑定相同的事件类型,然后以命名空间不同按需调用。

    $(function() {
        $("div").bind("click",function() {
            $("body").append("<p>click 事件</p>");
        });
        $("div").bind("click.plugin",function() {
            $("body").append("<p>click.plugin 事件</p>");
        });
        $("button").click(function() {
            $("div").trigger("click!");     // 注意click后面的感叹号
        });
    });

当单击<div>元素后,会同时触发click事件和click.plugin事件。如果只是单击button元素,则只触发click事件,而不触发click.plugin事件。注意,trigger("click!")后面的感叹号的作用是匹配所有不包含在命名空间中的click方法。

如果需要两者都被触发:

    $("div").trigger("click");

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350

推荐阅读更多精彩内容