3

我正在寻找最佳实践建议。

我正在编写一个小的 jQuery 插件来管理元素的水平滚动。

我需要该插件针对的所有 dom 元素来更新窗口调整大小。

事实是,我的网站是一个完整的 ajax “应用程序”,所以当我删除 DOM 元素时,我需要它们消失,这样内存就不会泄漏。

但是我找不到在不保留对 DOM 节点的引用的情况下绑定 resize 事件的方法。

编辑 :

实际上,我需要调整大小处理程序来在“调用”时获取以插件为目标的元素,因为我不想在内存中保留对这些元素的任何引用,因为我可能会在他们的父级上调用 .html('') ...

我没有粘贴我所有的代码,只是一个空壳。我已经有一个取消绑定处理程序的销毁方法。但是我正在动态生成、删除和附加 html 节点,并且我将插件所针对的元素以静默方式删除。

Kevin B 表示我可以重写 jQuery.remove方法来处理处理程序,但必须加载 jQuery UI 才能使其工作。我也不想这样。。

这是我尝试过的(尝试评论):

(function($) {
    // SOLUTION 2 (see below too)
    // Not good either coz elements are not removed until resize is triggered
    /*
    var hScrolls = $([]);
    $(window).bind('resize.hScroll',function(){
        if(!hScrolls.length) return;
        hScrolls.each(function(){
            if($(this).data('hScroll')) $(this).hScroll('updateDimensions');
            else hScrolls = hScrolls.not($(this));
        });
    });
    */
    // END SOLUTION 2

    // SOLUTION 3 (not implemented but I think I'm on the right path)
    $(window).bind('resize.hScroll',function(){
        // need to get hScroll'ed elements via selector...
        $('[data-hScroll]').hScroll('updateDimensions');
        // I don't know how....
    });
    // END SOLUTION 3
    var methods = {
        init : function(options) {
            var settings = $.extend( {
                defaults: true
            }, options);

            return this.each(function() {
                var $this = $(this),
                    data = $this.data('hScroll');
                if (!data) {
                    $this.data('hScroll', {
                        target: $this
                    });
                    // SOLUTION 1
                    // This is not good: it keeps a reference to $this when I remove it...
                    /*
                    $(window).bind('resize.hScroll', function(){
                        $this.hScroll('updateDimensions');
                    });
                    */
                    // END SOLUTION 1
                    $this.hScroll('updateDimensions');

                    // SOLUTION 2 (see above too)

                    hScrolls = hScrolls.add(this);

                }
            });
        },
        updateDimensions: function(){
            var hScroll = this.data('hScroll');
            // do stuff with hScroll.target
        }
    }

    $.fn.hScroll = function(method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if ( typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.hScroll');
        }
    };
})(jQuery);​

提前谢谢大家!

4

3 回答 3

2

cleanData每当您执行删除或替换元素的操作时,jQuery 都会调用(是的,即使您使用parent.html(""))。您可以通过扩展它并让它触发目标元素上的事件来利用它。

// This is taken from https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 10/17/2012
if (!$.widget) { // prevent duplicating if jQuery ui widget is already included
    var _cleanData = $.cleanData;
    $.cleanData = function( elems ) {
        for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
            try {
                $( elem ).triggerHandler( "remove" );
                // http://bugs.jquery.com/ticket/8235
            } catch( e ) {}
        }
        _cleanData( elems );
    };
}

现在,您可以在设置插件时绑定到 remove 事件并让它运行您的 destroy 方法。

$(elem).bind("remove",methods.destroy)
于 2012-10-17T15:50:30.760 回答
1

您可以使用类名并转发调整大小事件:

$.fn.hScroll = function(method) {
    this
      .addClass('hScroll')
      .data('method', arguments)
};

var methods['alert_text'] = function(config){
  alert( config + " " + $(this).text() );
}

$(window).bind('resize.hScroll',function(){
  $(".hScroll").each(function(){
     var method_config = $(this).data('method');
     var method = method_config.shift();
     // Forward the resize event with all resize event arguments:
     methods[method].apply(this, method_config);
   })
})

// Register a resize event for all a.test elements:
$("a.test").hScroll('alert_text', "hey");
// Would alert "hey you" for <a class="test">you</a> on every resize

更新

如果您更改 dom 并希望保留选择器,您可以试试这个:

var elements = [];
 $.fn.hScroll = function(method) {
     elements.push({'selector' : this.selector, 'arguments' : arguments });
 };

var methods['alert_text'] = function(config){
  alert( config + " " + $(this).text() );
}

$(window).bind('resize.hScroll',function(){
  $.each(elements,function(i, element){
    $(element.selector).each(function(){
       var method_config = element.arguments;
       var method = method_config.shift();
       // Forward the resize event with all resize event arguments:
       methods[method].apply(this, method_config);
     })
   })
})

// Register a resize event for all a.test elements:
$("a.test").hScroll('alert_text', "hey");
$(document.body).html("<a class='test'>you</a>");
// Would alert "hey you" for every window resize
于 2012-10-17T15:30:14.487 回答
0

您应该在扩展中绑定滚动事件。此外,您还需要为您的扩展添加一个“销毁”方法。在从 DOM 中删除元素之前,您需要调用此方法。在 detroy 方法内部是您想要取消绑定 resize 事件的地方。

完成这项工作的一件重要事情是,您可以引用绑定到 resize 事件的每个处理程序方法。或者,您可以在删除元素时取消绑定所有调整大小事件,然后将滚动事件重新绑定到需要它的其余元素。

于 2012-10-17T15:34:26.163 回答