在插件中保持DOM元素的引用

时间:2015-11-09 10:21:29

标签: jquery jquery-plugins

我正在编写一个插件,我想保留我调用插件的DOM元素的引用

代码看起来像

;(function ( $, window, document, undefined ) {
    "use strict";

    var $elem = $(this);    

    var methods = {
        /**
         * __constructor method
         * @param {} user defined options
         */
         init: function( options ) {

            $elem = (this);

            /**
             * save options
             */
            options = $.extend( true, {}, $.fn.xyz.defaults, options );
            $elem.data('options', options);

            console.info($elem);
         },

        /**
         * Attachs window's scroll event
         */
        attach: function(  ) {
            var w = $(window);
            w.on( 'scroll', methods._load);
            return this;
        },


        detach: function() {
            var w = $(window);  
            w.off( 'scroll', methods._load);    
        },

        /**
         * Tests it the DIV is within viewport
         */
        _visible: function() {
            var w = $(window);  

            return w.scrollTop() + w.height() >= $elem.offset().top;
        },


        _load: function() {
            if( methods._visible() ) {
                console.info("load data");      
                methods.detach();
            }
        }


    }





    $.fn.xyz = function() {
        var _this = $(this);


        if(!_this[0]) return _this;  // stop here if the container does not exist

        methods.init.apply( _this, arguments );
        return methods.attach.apply( _this );

    }

    $.fn.xyz.defaults = {
        onSuccess: false,
        onFailure: false,
        data: {}
    }

})( jQuery, window, document );

我的问题是在方法中我想要使用这个插件的DOM元素的引用

在这种情况下

_visible method

我想测试DOM现在是否在可见区域

return w.scrollTop() + w.height() >= $elem.offset().top;

我不知道如何跟踪方法中的DOM元素,好像有多个元素,那么我如何引用正确的DOM元素。

1 个答案:

答案 0 :(得分:2)

您的var $elem = $(this);无法可靠地运行,因为它的范围是整个插件的范围,而不是任何特定的调用范围。

相反,请确保:

    编写
  • 方法,使得this是正在执行的jQuery集合。
  • 方法以这样的方式调用/传递,即指定它们的上下文this。为此,您需要熟悉.call().apply().bind()

以下是经过修改的代码,包括进一步改进(未经测试):

;(function ($, window, document, undefined) {
    "use strict";

    var pluginName = 'xyz'; //avoids potential repetition throughout the plugin

    // `defaults` can be defined here.
    // Like `methods` it will remain available due to closure.
    var defaults = {
        onSuccess: false,
        onFailure: false,
        data: {}
    };

    var methods = {
        /**
         * __constructor method
         * @param {} user defined options
         */
        init: function( options ) {
            // Each element in the collection should get its own *independent* options.
            // This immunises every element against future destruction or changes made to other elements' options.
            return this.each(function() {
                $( this ).data( pluginName+'Data', $.extend( true, {}, defaults, options ) );
            });
         },
        /**
         * Attaches window.onScroll handler(s)
         */
        attach: function() {
            // The attached handler is now subject to `.bind()` and, as a function in its own right, can't be removed with `$(window).off( 'scroll', methods._load);`.
            // A reference to each bound instance needs to be kept to allow it to be detached independently of any others.
            // The most convenient scope for each element to store a reference to *its* scroll handler is the data object established in init().
            return this.each(function() {
                var $this = $( this );
                var data = $this.data( pluginName+'Data' );
                data.scrollHandler = methods._load.bind( $this );
                $(window).on( 'scroll', data.scrollHandler );
            });
        },
        /**
         * Detaches window.onScroll handler(s)
         */
        detach: function() {
            return this.each(function() {
                var scrollHandler = $( this ).data( pluginName+'Data' ).scrollHandler;
                if( scrollHandler ) {
                    $( window ).off( 'scroll', scrollHandler );
                }
            });
        },
        /**
         * Tests it the DIV is within viewport
         */
        _visible: function() {
            var w = $( window );
            return w.scrollTop() + w.height() >= this.offset().top;
        },
        _load: function() {
            return this.each(function() {
                var $this = $( this );
                if( methods._visible.call( $this ) ) {
                    methods.detach.call( $this );
                }
            });
        }
    }
    $.fn[pluginName] = function() {
        var _this = this; // `this` is already a jQuery collection object, so no need for $(this).
        if(!_this[0]) return _this;  // stop here if the collection is empty
        methods.init.apply(_this, arguments);
        return methods.attach.call(_this);
    }
})(jQuery, window, document);