zoukankan      html  css  js  c++  java
  • JQuery 支持 hide 和 show 事件的方法与分析

    问题提出

       JQuery不支持hide和show作为事件形式出现, 实际上这两个仅仅是JQuery对象的一个方法(fn);

    有一类UI交互需求,根据一个DOM对象的或者显示对附属的DOM对象做相同操作,

    一般情况下, 利用jquery hide和show方法的扩展参数中的回调函数,是可以实现的,例如:

      $( "#book" ).hide( "slow", function() {
         $( "#booklet" ).hide()
      });

       如果附属DOM是一个动态生成的插件,则在主DOM的hide中处理附DOM的隐藏, 就破坏了动态生成插件的灵活性,

    因为需要让使用对象(主DOM)自行添加同步显示和隐藏代码。例如 每一篇随笔的 TAG 可以自己输入,

    也可以从历史记录中选择, 这个选择插件就属于动态生成的, 如果在某种交互条件下,需要隐藏掉 TAG, 

    须要使用 hide 的回调函数处理。

    解决方法

      如果jq支持hide和show可以设置事件,并且在hide()和show()调用的时候被触发,

    类似一般的click事件绑定和触发, 则可以解决此问题(插件来设置其目标DOM的hide和show事件,

    完成自身的显示隐藏,而不是目标在hide方法中完成,这样只需要在插件的HTML中设置目标ID即可)。

      但是在jq官网上没有找到hide作为事件,实施上确实没有,

    应该是这个不是常规事件, 不是由用户能够触发的,故没有涉及为事件,可以理解为动作。

      在网上找到前辈的足迹, 并且找到解决方案。

     http://stackoverflow.com/questions/2857900/onhide-type-event-in-jquery

    http://jsfiddle.net/mofle/eZ4X3/

      查看jsfiddle有例子,只需要扩展一下JQ框架

    (function($) {
        $.each(['show','hide'], function(i, val) {
            var _org = $.fn[val];
            $.fn[val] = function() {
                this.trigger(val);
                return _org.apply(this, arguments);
            };
        });
    })(jQuery);

    方法分析

      上面的方法是对JQ框架实现hide和show方法的扩展, 我们来看下JQ是怎么实现这两个方法的:

    jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
        var cssFn = jQuery.fn[ name ];
        jQuery.fn[ name ] = function( speed, easing, callback ) {
            return speed == null || typeof speed === "boolean" ?
                cssFn.apply( this, arguments ) :
                this.animate( genFx( name, true ), speed, easing, callback );
        };
    });

      看样是都是跟fn有关, 上面提供的解决方案相当于对 JQ fn的做了继承,

    除了 保证原有fn内容(函数)执行 (return _org.apply(this, arguments);),

    还增加了 对 hide 和 show 事件的触发(this.trigger(val);)。

    fn与$()获得的对象

      那么, fn 到底是什么东西? 跟 $()获得的JQ对象有什么关系?

    还是要从刀勒符说起, 首先  $  ==  JQuery 的, 然后$就是一个函数, 函数内容如下:

        // Define a local copy of jQuery
        jQuery = function( selector, context ) {
            // The jQuery object is actually just the init constructor 'enhanced'
            // Need init if jQuery is called (just allow error to be thrown if not included)
            return new jQuery.fn.init( selector, context );
        },

       这样使用$符号获取的 JQuery对象, 实际就是 构造函数 jQuery.fn.init new出来的对象,

    jQuery.fn.init 此函数定义如下, 其中this表示new出来的对象, 可以看出为 array 形式的对象, 
    然后, init == jQuery.fn.init , new jQuery.fn.init == new init,
    故$()对象继承了init.prototype, 即 我们刚开始关注的 jQuery.fn, 这样, fn中任何函数,
    对于$()对象都可以直接调用 即 $().hide();
        init = jQuery.fn.init = function( selector, context ) {
                   ......
    
            return jQuery.makeArray( selector, this );
        };
    
    // Give the init function the jQuery prototype for later instantiation
    init.prototype = jQuery.fn;
     

     事件与trigger

      那么为什么 bind("hide", function(e){}) 的事件 hide , 可以被  this.trigger("hide"); 触发调用,

    这其中又有哪些道道?

      bind 间接调用on, on与bind一样同为 jQuery.fn 的一个函数, 可以被$()对象调用,

    on调用实际上执行, 是对$()对象数组中的每一个DOM元素 调用了 jQuery.event.add

        bind: function( types, data, fn ) {
            return this.on( types, null, data, fn );
        },
    jQuery.fn.extend({
    
        on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
                   .......
            return this.each( function() {
                jQuery.event.add( this, types, fn, data, selector );
            });
        },

      从下面的代码轨迹, 看出 bind 将新的事件对象(handleObj)存入了  DOM 对象(elem)的 events[ type ]

    jQuery._data( elem ).events[ type ]
    jQuery.event = {
    
        global: {},
    
        add: function( elem, types, handler, data, selector ) {
            var tmp, events, t, handleObjIn,
                special, eventHandle, handleObj,
                handlers, type, namespaces, origType,
                elemData = jQuery._data( elem );
                    ......
    
            // Init the element's event structure and main handler, if this is the first
            if ( !(events = elemData.events) ) {
                events = elemData.events = {};
            }
                    .......
                // Init the event handler queue if we're the first
                if ( !(handlers = events[ type ]) ) {
                    handlers = events[ type ] = [];
                    handlers.delegateCount = 0;
                                    ........
                }
    
                           .......
    
                // Add to the element's handler list, delegates in front
                if ( selector ) {
                    handlers.splice( handlers.delegateCount++, 0, handleObj );
                } else {
                    handlers.push( handleObj );
                }
                            .......

         

      同样 trigger fn也是从 jQuery._data( elem ).events[ type ] 获取 当前事件的 处理函数 handle, 然后handle在当前对象上执行。

        trigger: function( event, data, elem, onlyHandlers ) {
            var handle, ontype, cur,
                bubbleType, special, tmp, i,
                eventPath = [ elem || document ],
                type = hasOwn.call( event, "type" ) ? event.type : event,
                namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
    
            cur = tmp = elem = elem || document;
                   ........
                // jQuery handler
                handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
                if ( handle ) {
                    handle.apply( cur, data );
                }
                     .........

    问题解决代码

      阴影部分为“插件"代码, 可以单独裁减掉, 而不修改 first div控件原有代码。

    <html>
    <head>
    <title>Example</title>
    <script type="text/javascript" src="./jquery.js"></script>
    </head>
    <body>
    
    <div id="first" style="100px; height:100px; background: green">first</div>
    <div id="second" style="100px; height:100px; background: yellow" targetDOMID="first">second</div>
    
    <input type="button" value="show first" id="showFirst"/>
    <input type="button" value="hide first" id="hideFirst"/>
    
    <script type="text/javascript">
    (function($) {
        $.each(['show','hide'], function(i, val) {
            var _org = $.fn[val];
            $.fn[val] = function() {
                this.trigger(val);
                return _org.apply(this, arguments);
            };
        });
    })(jQuery);
    
    /* 插件DOM, 给目标DOM(第一个div)添加 隐藏/显示 事件, 
        事件触发后, 第二个div也隐藏/显示 */
    var targetDOMID = $("#second").attr("targetDOMID");
    var targetDOM = $("#"+targetDOMID);
    targetDOM.bind("hide", function(){
        $("#second").hide();
    })
    .bind("show", function(){
        $("#second").show();
    });
    
    /* 按钮click事件触发 第一块div 的显示和隐藏fn */
    $("#showFirst").click(function(){
        $("#first").show();
    })
    $("#hideFirst").click(function(){
        $("#first").hide();
    })
     
    </script>
     
    </body>
    </html>
  • 相关阅读:
    JDK、J2EE、J2SE、J2ME的区别
    消息队列
    Unity3D 导入aar注意事项
    汇编小结
    构造函数语意学--笔记
    androidStudio 改包名
    新手用车
    北京临牌办理与续办
    h5+
    apache.http.MalformedChunkCodingException: Chunked stream ended unexpectedly
  • 原文地址:https://www.cnblogs.com/lightsong/p/3751484.html
Copyright © 2011-2022 走看看