3

ベストプラクティスのアドバイスを探しています。

要素の水平スクロールを管理する小さな jQuery プラグインを作成しています。

ウィンドウのサイズ変更時に更新するには、そのプラグインの対象となるすべての dom 要素が必要です。

実際、私のウェブサイトは完全な ajax 'アプリ' であるため、DOM 要素を削除するときは、メモリ リークを防ぐために削除する必要があります。

しかし、DOM ノードへの参照を保持せずにサイズ変更イベントをバインドする方法が見つかりません。

編集 :

実際には、「呼び出し」時にプラグインをターゲットとする要素を取得するためにサイズ変更ハンドラーが必要です。これらの要素への参照をメモリに保持したくないので、それらの要素の親で .html('') を呼び出す可能性があるためです。 ...

すべてのコードを貼り付けたのではなく、空のシェルだけを貼り付けました。ハンドラーのバインドを解除する destroy メソッドが既にあります。しかし、HTML ノードを動的に生成、削除、および追加しています。プラグインの対象となる要素をサイレント モードで削除します。

Kevin B は.remove、ハンドラーを処理するために jQuery メソッドをオーバーライドできるが、機能させるには 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

jQuery はcleanData、要素を削除または置換する何かを行うたびに呼び出します (はい、 を使用していても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

拡張機能にスクロール イベントをバインドする必要があります。また、「destroy」メソッドも拡張機能に追加する必要があります。要素を DOM から削除する前に、このメソッドを呼び出す必要があります。detroy メソッド内で、サイズ変更イベントのバインドを解除します。

これを機能させる上で重要なことの 1 つは、サイズ変更イベントにバインドされている各ハンドラー メソッドへの参照を持っていることです。または、要素の削除時にすべてのサイズ変更イベントのバインドを解除してから、スクロール イベントをそれを必要とする残りの要素に再バインドすることもできます。

于 2012-10-17T15:34:26.163 に答える