浅谈jQuery事件绑定原理

jq里面有一个data的方法,给dom元素绑定相关的数据的。当给dom用jq的方法绑定了事件,会生成对应的时间列表
可以看下面的例子(请在firefox中查看 因为firefox中对象支持toSource())

代码如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title></title>
</head>
<body>
<div id="test"></div>
<script type="text/javascript" src="http://common.cnblogs.com/script/jquery.js"></script>
<script type="text/javascript">
    window.onload = function(){
        alert($.data($('#test')[0],'events'));//null
        alert($.data($('#test')[0],'handle'));//null
        $('#test')
        .bind('click',function(){
            alert(1)
        })
        .bind('mouseover',function(){
            alert(2)
        })
        .bind('click',function(){
            alert(3)
        })
        .bind('click',function(){
            alert(4)
        })
        alert($.data($('#test')[0],'events').toSource());//时间列表
        alert($.data($('#test')[0],'handle').toSource());//执行的函数
    }
</script>
</body>
</html>

data是给元素绑定数据的
数据源是 cache对象
当元素绑定数据的时候 会给元素添加一个属性   jQueryxxx      xxx为执行jq的时间戳
这里要说明一下,有一个uuid 他是累加的
jQueryxxx的值就是这个uuid
cache 的 key就是这个 uuid
value就是要存的数据
data对于事件的绑定是很重要的................................

代码如下:

function now(){ 
    return +new Date; 
};
var win     = this,
    expando = "jQuery" + now(), 
       uuid    = 0,  
      cache   = {};
win.data = function(elem, name, data){ 
    var id = elem[expando]; 
    if(!id) 
        id = elem[expando] = ++uuid; 
    if(name&&!cache[id]) 
        cache[id] = {}; 
    if(data !== undefined) 
        cache[id][name] = data; 
    return name 
        ? cache[id][name] 
        : id; 
}
win.removeData = function(elem, name){ 
    var id = elem[expando]; 
    if (name){ 
        if (cache[id]) { 
            delete cache[id][name]; 
            name = ""; 
            for ( name in cache[ id ] ) 
                break; 
            if ( !name ) 
                removeData(elem); 
        }  
    }else{   
            try { 
                delete elem[expando]; 
            } catch(e){ 
                if ( elem.removeAttribute ) 
                    elem.removeAttribute( expando ); 
            } 
            delete cache[id]; 
    } 
}

win.each = function( object, callback, args ) { 
    var name, i = 0, length = object.length; 
    if ( args ) { 
        if ( length === undefined ) { 
            for ( name in object ) 
                if ( callback.apply( object[ name ], args ) === false ) 
                    break; 
        } else 
            for ( ; i < length; ) 
                if ( callback.apply( object[ i++ ], args ) === false ) 
                    break; 
    } else { 
        if ( length === undefined ) { 
            for ( name in object ) 
                if ( callback.call( object[ name ], name, object[ name ] ) === false ) 
                    break; 
        } else 
            for ( var value = object[0]; 
                i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} 
    } 
    return object; 
}

接着实现添加事件

jq里面是在 jQuery.event里面的add方法
在add方法里面实现了一下一些功能
取元素的events,handle这2个data绑定的数据
events存放的是事件列表
格式如下
{
click: [{handler:function(){},type:"click",guid:'xx'}.......],
mouse:[......]
}
handle是执行的函数
(所有的执行函数都是一样的 他们遍历事件列表    执行对应的事件)
然后遍历types   因为可以绑定多个事件
回调函数也会给几个属性
假设回调函数是handler
handler.guid = gevent.guid++
handler.type =  name
name应该算一个特殊的命名  方便删除用的
比如
$('#xx')
.bind('click',function(){})
.bind('click.d',handler)
name就是d了
删除的时候可以只删除d那个事件  不删除上面的那个 click事件
 
最后是给元素绑定事件 但是执行的函数都是
function(){
 gevent.handle.apply(arguments.callee.elem, arguments);
});

代码如下:

win.gevent = {
    guid : 1,
    add  : function (elem, types, handler){
        if ( elem.nodeType == 3 || elem.nodeType == 8 )
            return;
        if ( elem.setInterval && elem != window )
            elem = window;
        //给函数一个唯一标识的索引  方便后面删除该事件   
        if ( !handler.guid )
            handler.guid = this.guid++;
        //获得该元素的events handle 下的数据   
        var events = data(elem, "events") || data(elem, "events", {}),
            handle =data(elem, "handle") || data(elem, "handle", function(){
                //gevent.handle才是各种行为触发后会执行的函数
                gevent.handle.apply(arguments.callee.elem, arguments);
            });
        handle.elem = elem;
        //遍历事件名 因为可以是 click mouseover
        each(types.split(/\s+/), function(index, type) {
            var namespaces = type.split(".");
            //获得事件名
            type = namespaces.shift();
            //去掉点后面的东西 是个特殊的命名  在删除的时候可以指定删除他  如 click.d
            //用事件的type 记录住这个特殊的命名
            handler.type = namespaces.slice().sort().join(".");
            //获得该事件是否已经存在events 这个对象里面了
            var handlers = events[type];
            //如果不存在该事件 给元素绑定该事件               
            if (!handlers) {
                handlers = events[type] = {};
                if (elem.addEventListener)
                    elem.addEventListener(type, handle, false);
                else if (elem.attachEvent)
                    elem.attachEvent("on" + type, handle);                                       
            }
            //吧函数放到元素的该事件的列表里面
            handlers[handler.guid] = handler;                                       
        });
        elem = null;                                                   
    }
}

gevent.hander是绑定事件真正执行的函数
在gevent.hander里面也有取.特殊命名的地方  但是不知道做什么用的
hander里面先对event进行包装
包装见gevent. fix 和 setEvent
主要是对做一个原生event的一个copy  然后把不兼容的方法  都合成兼容的写法
然后取元素的events (事件列表)
然后遍历这个事件列表  判断type是不是事件列表的key 是的话就执行事件
在执行列表函数的时候会判断返回值
如果返回false  还可以组织事件冒泡 和 默认行为

代码如下:

win.gevent = {
    handle : function(event){
        var all, handlers;
        //包装event
        event = arguments[0] = gevent.fix( event || window.event );
        event.currentTarget = this;
        //这里的........
        var namespaces = event.type.split(".");
        event.type = namespaces.shift();
        all = !namespaces.length;
        var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
        //取这个元素的该行为 的 事件列表
        handlers = (data(this, "events") || {} )[event.type];           
        //遍历这个事件列表 执行该执行的东西
        for ( var j in handlers ) {
            var handler = handlers[j];
            if ( all || namespace.test(handler.type) ) {
                // Pass in a reference to the handler function itself
                // So that we can later remove it
                // jq上的注释是是这么写的 把event的handler 引用这个事件 方便之后移除
                // 但是在remove里面 并没有用到event的handler  不知道这里到底有什么用  且有多个事件的时候这个事件被取代
                event.handler = handler;
                //执行事件 并且是用元素调用的事件 可以吧事件里面的this执行元素 ret为函数的返回值
                var ret = handler.apply(this, arguments);
                //如果有返回值  且返回值是false 执行阻止事件冒泡 阻止执行事件默认行为                       
                if( ret !== undefined ){
                    event.result = ret;
                    if ( ret === false ) {
                        event.preventDefault();
                        event.stopPropagation();
                    }
                }   
            }               
        }
    },
    props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),       
    fix : function(event){
        //new setEvent会给event给以个expando属性 如果有中个属性 说明已经生成了event了 不需要在次对event进行包装
        if ( event[expando] )
            return event;
        //保留一个原始的event
        // new一个新的event 这个与原始的event是不同的
        var originalEvent = event;
        event = new setEvent( originalEvent );
        //获得原始event的属性值  有哪些属性值 见 this.props
        for ( var i = this.props.length, prop; i; ){
            prop = this.props[ --i ];
            event[ prop ] = originalEvent[ prop ];
        }
        //将目标元素同一成event.target
        if ( !event.target )
            event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
        //如果发现是文本节点 取他的父节点
        if ( event.target.nodeType == 3 )
            event.target = event.target.parentNode;
       
        if ( !event.relatedTarget && event.fromElement )
            event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;                           
        return event;
    }       
}
win.setEvent = function(src){
    // Allow instantiation without the 'new' keyword
    // Event object
    if( src && src.type ){
        this.originalEvent = src;
        this.type = src.type;
    // Event type
    }else
        this.type = src;
    // timeStamp is buggy for some events on Firefox(#3843)
    // So we won't rely on the native value
    this.timeStamp = now();
    // Mark it as fixed
    this[expando] = true;
}
function returnFalse(){
    return false;
}
function returnTrue(){
 return true;
}
setEvent.prototype = {
 preventDefault: function() {   
     var e = this.originalEvent;
     if( !e )
         return;
     // if preventDefault exists run it on the original event
     if (e.preventDefault)
         e.preventDefault();
     // otherwise set the returnValue property of the original event to false (IE)
     e.returnValue = false;
 },
 stopPropagation: function() {   
     var e = this.originalEvent;
     if( !e )
         return;
     // if stopPropagation exists run it on the original event
     if (e.stopPropagation)
         e.stopPropagation();
     // otherwise set the cancelBubble property of the original event to true (IE)
     e.cancelBubble = true;
 },
 stopImmediatePropagation:function(){
     this.isImmediatePropagationStopped = returnTrue;
     this.stopPropagation();
 },
 isImmediatePropagationStopped: returnFalse
};

一个完整的例子

代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title></title>
</head>
<body>
<div id="vv" style="height:200px;width:200px; background-color:#f00; padding:20px;">
<div id="xx" style="height:200px;width:200px; background-color:#000000;"></div>
</div>
<script type="text/javascript">
(function(doc,undefined){
function now(){
return +new Date;
};
var win     = this,
expando = "jQuery" + now(),
uuid    = 0,
cache   = {};
win.data = function(elem, name, data){
var id = elem[expando];
if(!id)
id = elem[expando] = ++uuid;
if(name&&!cache[id])
cache[id] = {};
if(data !== undefined)
cache[id][name] = data;
return name
? cache[id][name]
: id;
}
win.removeData = function(elem, name){
var id = elem[expando];
if (name){
if (cache[id]) {
delete cache[id][name];
name = "";
for ( name in cache[ id ] )
break;
if ( !name )
removeData(elem);
}
}else{
try {
delete elem[expando];
} catch(e){
if ( elem.removeAttribute )
elem.removeAttribute( expando );
}
delete cache[id];
}
}
win.each = function( object, callback, args ) {
var name, i = 0, length = object.length;
if ( args ) {
if ( length === undefined ) {
for ( name in object )
if ( callback.apply( object[ name ], args ) === false )
break;
} else
for ( ; i < length; )
if ( callback.apply( object[ i++ ], args ) === false )
break;
} else {
if ( length === undefined ) {
for ( name in object )
if ( callback.call( object[ name ], name, object[ name ] ) === false )
break;
} else
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
}
return object;
}
win.gevent = {
guid : 1,
add  : function (elem, types, handler){
if ( elem.nodeType == 3 || elem.nodeType == 8 )
return;
if ( elem.setInterval && elem != window )
elem = window;
//给函数一个唯一标识的索引  方便后面删除该事件
if ( !handler.guid )
handler.guid = this.guid++;
//获得该元素的events handle 下的数据
var events = data(elem, "events") || data(elem, "events", {}),
handle =data(elem, "handle") || data(elem, "handle", function(){
//gevent.handle才是各种行为触发后会执行的函数
gevent.handle.apply(arguments.callee.elem, arguments);
});
handle.elem = elem;
//遍历事件名 因为可以是 click mouseover
each(types.split(/\s+/), function(index, type) {
var namespaces = type.split(".");
//获得事件名
type = namespaces.shift();
//去掉点后面的东西 是个特殊的命名  在删除的时候可以指定删除他  如 click.d
//用事件的type 记录住这个特殊的命名
handler.type = namespaces.slice().sort().join(".");
//获得该事件是否已经存在events 这个对象里面了
var handlers = events[type];
//如果不存在该事件 给元素绑定该事件
if (!handlers) {
handlers = events[type] = {};
if (elem.addEventListener)
elem.addEventListener(type, handle, false);
else if (elem.attachEvent)
elem.attachEvent("on" + type, handle);
}
//吧函数放到元素的该事件的列表里面
handlers[handler.guid] = handler;
});
elem = null;
},
remove: function(elem, types, handler) {
if ( elem.nodeType == 3 || elem.nodeType == 8 )
return;
//获取这个元素的所有行为列表  如 {click:{},mouseocer:{}}
var events = data(elem, "events"), ret, index;
if(events){
//如果没出入行为类型 则删除这个元素的所有事件
//如果传入的是.xx这种形式的 把所有行为的包含.xx命名的全部干掉
if ( types === undefined || (typeof types === "string" && types.charAt(0) == ".") ){
for ( var type in events )
this.remove( elem, type + (types || "") );
}else{
//不知道干嘛的
if ( types.type ) {
handler = types.handler;
types = types.type;
}
//因为删除事件可以一次支持删除多个 如click mouseover  所有要遍历删除
each(types.split(/\s+/),function(index, type){
var namespaces = type.split(".");
type = namespaces.shift();
var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
if ( events[type] ) {
//如果传了第3个参数 函数  则删除这个事件
if ( handler )
delete events[type][handler.guid];
else{
//遍历中个这个的所有行为
for ( var handle in events[type] ){
// Handle the removal of namespaced events
//删除有特殊命名的函数
//如果没有特殊命名 正则 则是/^|..|$/ 可以匹配空 所以也能删除掉没有特殊命名的函数
if ( namespace.test(events[type][handle].type) )
delete events[type][handle];
}
}
}
for ( ret in events[type] ) break;
//如果events[type]变成空的了 也就是{} 删除这个元素的的绑定事件
if ( !ret ) {
if (elem.removeEventListener)
elem.removeEventListener(type, data(elem, "handle"), false);
else if (elem.detachEvent)
elem.detachEvent("on" + type, data(elem, "handle"));
ret = null;
delete events[type];
}
});
}
for ( ret in events ) break;
//如果发现元素的整个events都是空的了
//清空掉handle 并且清空掉他所有的引用
if ( !ret ) {
var handle = data( elem, "handle" );
if ( handle ) handle.elem = null;
removeData( elem, "events" );
removeData( elem, "handle" );
}
}
},
handle : function(event){
var all, handlers;
//包装event
event = arguments[0] = gevent.fix( event || window.event );
event.currentTarget = this;
//这里的........
var namespaces = event.type.split(".");
event.type = namespaces.shift();
all = !namespaces.length;
var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
//取这个元素的该行为 的 事件列表
handlers = (data(this, "events") || {} )[event.type];
//遍历这个事件列表 执行该执行的东西
for ( var j in handlers ) {
var handler = handlers[j];
if ( all || namespace.test(handler.type) ) {
// Pass in a reference to the handler function itself
// So that we can later remove it
// jq上的注释是是这么写的 把event的handler 引用这个事件 方便之后移除
// 但是在remove里面 并没有用到event的handler  不知道这里到底有什么用  且有多个事件的时候这个事件被取代
event.handler = handler;
//执行事件 并且是用元素调用的事件 可以吧事件里面的this执行元素 ret为函数的返回值
var ret = handler.apply(this, arguments);
//如果有返回值  且返回值是false 执行阻止事件冒泡 阻止执行事件默认行为
if( ret !== undefined ){
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
},
props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix : function(event){
//new setEvent会给event给以个expando属性 如果有中个属性 说明已经生成了event了 不需要在次对event进行包装
if ( event[expando] )
return event;
//保留一个原始的event
// new一个新的event 这个与原始的event是不同的
var originalEvent = event;
event = new setEvent( originalEvent );
//获得原始event的属性值  有哪些属性值 见 this.props
for ( var i = this.props.length, prop; i; ){
prop = this.props[ --i ];
event[ prop ] = originalEvent[ prop ];
}
//将目标元素同一成event.target
if ( !event.target )
event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
//如果发现是文本节点 取他的父节点
if ( event.target.nodeType == 3 )
event.target = event.target.parentNode;
if ( !event.relatedTarget && event.fromElement )
event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
return event;
}
}
win.setEvent = function(src){
// Allow instantiation without the 'new' keyword
// Event object
if( src && src.type ){
this.originalEvent = src;
this.type = src.type;
// Event type
}else
this.type = src;
// timeStamp is buggy for some events on Firefox(#3843)
// So we won't rely on the native value
this.timeStamp = now();
// Mark it as fixed
this[expando] = true;
}
function returnFalse(){
return false;
}
function returnTrue(){
return true;
}
setEvent.prototype = {
preventDefault: function() {
var e = this.originalEvent;
if( !e )
return;
// if preventDefault exists run it on the original event
if (e.preventDefault)
e.preventDefault();
// otherwise set the returnValue property of the original event to false (IE)
e.returnValue = false;
},
stopPropagation: function() {
var e = this.originalEvent;
if( !e )
return;
// if stopPropagation exists run it on the original event
if (e.stopPropagation)
e.stopPropagation();
// otherwise set the cancelBubble property of the original event to true (IE)
e.cancelBubble = true;
},
stopImmediatePropagation:function(){
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
isImmediatePropagationStopped: returnFalse
};
})(document);
var $ = function(id){return document.getElementById(id)}
var a = function(){alert(1)}
window.onload = function(){
gevent.add($('xx'),'click',a);
gevent.add($('xx'),'click',function(){alert(1)});
gevent.add($('xx'),'click',function(){alert(2)});
gevent.add($('xx'),'click',function(){alert(3)});
gevent.add($('xx'),'click.xx',function(){alert(4)});
}
</script>
</body>
</html>

以上内容只是自己的一些理解,水平有限,难免有错,望指正...

(0)

相关推荐

  • jquery 新建的元素事件绑定问题解决方案

    js的事件监听跟css不一样,css只要设定好了样式,不论是原来就有的还是新添加的,都有一样的表现.而事件监听不是,你必须给每一个元素单独绑定事件. 常见的例子是处理表格的时候.每行行末有个删除按钮,点了这个能够删除这一行. 复制代码 代码如下: <table> <tbody> <tr> <td>这行原来就有</td> <td><buttonclass="del">删除</button>&l

  • 解析jQuery的三种bind/One/Live事件绑定使用方法

    jQuery是 一款优秀的JavaScript框架,在旧版里主要用bind()方法,在新版里又多了两种One(),Live(),下面介绍这几种方法的使用: 1. bind/Unbind在jquery的事件模型中,有两个基本的事件绑 定函数,bind与unbind,这两个函数的含义就是匹配页面元素进行相关事件的处理.比如我们在JS中经常使用到的 onfocus,onblur,onmouseover,onmousedown等事件都可以作为bind的参数进行传递. $("#id").bind

  • 关于jQuery新的事件绑定机制on()的使用技巧

    今天浏览jQuery的deprecated列表,发现live()和die()在里面了,赶紧看了一下,发现从jQuery1.7开始,jQuery引入了全新的事件绑定机制,on()和off()两个函数统一处理事件绑定.因为在此之前有bind(), live(), delegate()等方法来处理事件绑定,jQuery从性能优化以及方式统一方面考虑决定推出新的函数来统一事件绑定方法并且替换掉以前的方法. on(events,[selector],[data],fn) events:一个或多个用空格分隔

  • jQuery事件绑定与解除绑定实现方法

    本文实例讲述了jQuery事件绑定与解除绑定实现方法.分享给大家供大家参考.具体如下: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title> New Document </title> <meta name=

  • JQuery中DOM事件绑定用法详解

    本文实例讲述了JQuery中DOM事件绑定用法.分享给大家供大家参考.具体分析如下: 在文档加载完成后,如果打算为元素绑定事件来完成某些操作,则可以使用bind()方法来对匹配元素进行特定事件的绑定,bind()方法的调用格式为: bind( type [, data] , fn); bind()方法有3个参数,说明如下. 第1个参数是事件类型,类型包括:blur.focus.load.resize.scroll.unload.click.dblclick.mousedown.mouseup.m

  • jQuery事件绑定.on()简要概述及应用

    前几天在看<jquery基础教程>,看到事件委托的时候,关于live()方法讲的不是很详细,就去搜了一下关于live()和delegate()的. 然后在一处看到live()已经被移除了,囧,然后去看了最新的jq源码,果然被移除了,现在是1.9.1版本,不知道live()是在之前哪个版本被移除的,惭愧啊,之前都没留意. 看源码发现bind()和delegate()都是由on()实现的.on()的描述如下: 复制代码 代码如下: .on( events [, selector ] [, data

  • jQuery文本框(input textare)事件绑定方法教程

    目前1.7以上,jquery​的事件绑定已经用on替换了原来的bind,接下来为大家介绍下bind的使用方法及input textare事件,感兴趣的朋友可以参考下 (1)jquery 绑定事件 目前1.7以上,jquery的事件绑定已经用on替换了原来的bind: 区别:(个人理解)bind是一次绑定事件到每一个子节点:on是只绑定到父节点,然后冒泡到各个子节点: 用法:bind 一个事件,一个方法:$(".class input").bind('click',function(e)

  • jQuery事件绑定用法详解(附bind和live的区别)

    本文实例分析了jQuery事件绑定用法.分享给大家供大家参考,具体如下: html: <a href="#" onclick="addBtn()">addBtn</a> <div id="mDiv"> <button class="cBtn" onclick="alert(11111)">button1</button> <button cl

  • jQuery事件绑定和委托实例

    本文实例讲述了jQuery事件绑定和委托.分享给大家供大家参考.具体方法如下: jQuery事件的绑定和委托可以用多种方法实现,on()  . bind()  . live()  . delegate() ,还有one().   有时我们可能会像下面这样绑定一个事件: 复制代码 代码如下: $("#div1").click(function() {      alert("点击后触发");  }); 上面的事件绑定,我们可以通过多种方式去实现:   1. on()

  • jQuery事件绑定on()、bind()与delegate() 方法详解

    啃了一段日子的js相关了,学的过程中发现在jQuery中绑定事件时,有人用bind(),有人用on(),有人用delegate(),还有人用live(),看代码的时候觉得都实现功能了也就掀过去了,只是一直没完全弄懂之间的区别,于是今天查了下资料,自己做个总结. 之所以有这么多类型的绑定方法,是因为jQuery的版本更新的原因,如on()方法就是1.7以后出现的. jQuery的事件绑定api页面上,提到live()方法已经过时,不建议使用.所以这里我们主要就看下以下三个方法:bind().del

  • jQuery实现按钮只点击一次后就取消点击事件绑定的方法

    本文实例讲述了jQuery实现按钮只点击一次后就取消点击事件绑定的方法.分享给大家供大家参考.具体实现方法如下: <input type="button" id="my-selector" value="只能点击一次" /> <script> $('#my-selector').bind('click', function() { $(this).unbind('click'); alert('Clicked and un

  • jQuery实现的事件绑定功能基本示例

    本文实例讲述了jQuery实现的事件绑定功能.分享给大家供大家参考,具体如下: HTML正文: 用户名:<input type="text" value="邮箱/用户名/手机号" id="login"/><br> 密 码:<input type="password" id="passwd"><br> <input type="button&qu

随机推荐