События jQuery применяются только к последнему элементу - PullRequest
3 голосов
/ 02 ноября 2011

Это немного сложнее. Я строю представление карусели, которое подключается во время загрузки с использованием jQuery.

Вот наценка:

<div class="carousel" data-direction="v" id="carousel1">
    <div class="card-cont">
        <div id="card1" class="card">This is Card 1</div>
        <div id="card2" class="card">This is Card 2</div>
        <div id="card3" class="card">This is Card 3</div>
        <div id="card4" class="card">This is Card 4</div>
    </div>
</div>

<div class="carousel" data-direction="h" id="carousel2">
    <div class="card-cont">
        <div id="card5" class="card">This is Card 1</div>
        <div id="card6" class="card">This is Card 2</div>
        <div id="card7" class="card">This is Card 3</div>
        <div id="card8" class="card">This is Card 4</div>
    </div>
</div>

Используя jQuery, я перебираю все элементы .carousel и подключаю функционал. Код является объектно-ориентированным, и я разместил здесь несколько jsFiddle> http://jsfiddle.net/eZbUB/

Проблема заключается в том, что всякий раз, когда у меня есть несколько каруселей на странице, события (то есть смена карты) применяются только к последней карусели на странице. у кого-нибудь есть решение? Функции позиционирования индикатора, размера и т. Д. Работают нормально. Вот полный код jQuery:

$(function(){
    $('.carousel').each(function() { Carousel.init($(this)); });
});

var Carousel = {

    container       : null,
    card_container  : null,
    cards           : [ ],
    card_width      : 0,
    no_cards        : 0,
    indicator       : { },
    current_card    : 0,
    direction       : 'h',

    init : function(container) {

        // Assin vars:
        var self             = this;
        this.container       = container;
        this.card_container  = this.container.find('.card-cont');
        this.cards           = this.container.find('div.card');
        this.card_width      = this.container.width();
        this.no_cards        = this.cards.length;
        this.direction       = $(this.container).attr('data-direction');

        // Size the container:
        this.card_container.width((this.card_width * this.no_cards))

        // Add an indicator:
        this.indicator = $('<ul class="card-indicator" />');
        this.indicator.items = [ ];

        if(this.direction == 'v') { this.indicator.addClass('vertical'); }

        for(var i = 0; i < this.no_cards; i++)
        {
            $(this.cards[i]).width(this.card_width);
            var indicator_item = $('<li />');
            indicator_item.click(function() { self.setCard($(this).index()); });
            this.indicator.append(indicator_item);
            this.indicator.items.push(indicator_item);

        }
        this.indicator.appendTo(this.container);

        // Position the indicator:
        if(this.direction == 'h')
        {
            var indicator_top_pos = ((this.container.offset().top + this.container.height()) - this.indicator.height());
            var indicator_left_pos = (this.container.width() - this.indicator.width()) / 2;
            this.indicator.css({ top: indicator_top_pos, left: indicator_left_pos });
        }
        else
        {
            var indicator_top_pos = (this.container.height() - this.indicator.height()) / 2;
            var indicator_left_pos = (this.container.offset().left + this.container.width()) - 20;
            this.indicator.css({ top: indicator_top_pos, left: indicator_left_pos });
        }

        // Add the current styles to everything:
        $(this.cards[0]).addClass('current');
        this.indicator.items[0].addClass('current');

        // Hook up the drag events:
        var mouse_start_x = 0;
        var mouse_end_x   = 0;
        var mouse_start_y = 0;
        var mouse_end_y   = 0;
        var direction_x   = null;
        var direction_y   = null;
        var next_index    = 0;

        this.container.mousedown(function(e) {
            mouse_start_x = e.pageX;
            mouse_start_y = e.pageY;
        });
        this.container.mouseup(function(e) {
            mouse_end_x = e.pageX;
            mouse_end_y = e.pageY;

            alert(self.container.attr('id'));

            if(mouse_end_x > mouse_start_x) { direction_x = 'right'; }
            if(mouse_end_x < mouse_start_x) { direction_x = 'left'; }
            if(mouse_end_y > mouse_start_y) { direction_y = 'down'; }
            if(mouse_end_y < mouse_start_y) { direction_y = 'up'; }

            switch(self.direction)
            {
                case 'v':
                    if(direction_y == 'down') { next_index = (self.current_card == 0) ? 0 : self.current_card - 1; }
                    if(direction_y == 'up')   { next_index = (self.current_card == (self.no_cards - 1)) ? self.current_card : self.current_card + 1; }
                    break;

                case 'h':
                default:
                    if(direction_x == 'right') { next_index = (self.current_card == (self.no_cards - 1)) ? self.current_card : self.current_card + 1; }
                    if(direction_x == 'left')  { next_index = (self.current_card == 0) ? 0 : self.current_card - 1; }
                    break;
            }
            self.setCard(next_index);
        });

        // Return the object (we use init as a constructor):
        return this;
    },

    // Function to check if we're on the last card:
    onLastCard : function() {
        return (this.current_card == (this.indicator.items.length - 1)) ? true : false;
    },

    // Function to check if we're on the first card:
    onFirstCard : function() {
        return (this.current_card == 0) ? true : false;
    },

    setCard : function(index) {
        // If the index matches the current one, don't do anything:
        if(index == this.current_card)
        {
            return;
        }
        else
        {
            // Calculate the left position we need to move:
            var new_left_pos = this.card_width * index;
            this.card_container.css({ left: -new_left_pos });
            this.indicator.items[this.current_card].removeClass('current');
            this.indicator.items[index].addClass('current');
            this.current_card = index;
            return true;
        }
    },
};

Я пробовал другие альтернативы (например, bind() и live(), но ни одна из них не сработала). Любая помощь с благодарностью получена.

Ответы [ 2 ]

5 голосов
/ 02 ноября 2011

То, как вы звоните Carousel.init, в init функция this всегда будет Carousel, то есть есть только один.Вот почему вы видите, что он применяется только к последнему.

Я бы посмотрел на переработку Carousel, чтобы она была функцией конструктора (та, которую вы используете с new),@Boo только что бросил new перед Carousel.init, что является хорошим началом, но создаваемый объект не будет иметь различных свойств, которые вы наделили Carousel.

Вотбыстрая переделка;оно полностью не проверено, но должно привести вас в правильном направлении:

// Scoping function so our various member functions can have proper names
var Carousel = (function() {

    // The constructor function    
    function Carousel() {
        // Assign vars:
        var self             = this; // Important for the event handler closures

        this.container       = container;
        this.card_container  = this.container.find('.card-cont');
        this.cards           = this.container.find('div.card');
        this.card_width      = this.container.width();
        this.no_cards        = this.cards.length;
        this.direction       = $(this.container).attr('data-direction');

        // Size the container:
        this.card_container.width((this.card_width * this.no_cards))

        // Add an indicator:
        this.indicator = $('<ul class="card-indicator" />');
        this.indicator.items = [ ];

        if(this.direction == 'v') { this.indicator.addClass('vertical'); }

        for(var i = 0; i < this.no_cards; i++)
        {
            $(this.cards[i]).width(this.card_width);
            var indicator_item = $('<li />');
            indicator_item.click(function() { self.setCard($(this).index()); });
            this.indicator.append(indicator_item);
            this.indicator.items.push(indicator_item);

        }
        this.indicator.appendTo(this.container);

        // Position the indicator:
        if(this.direction == 'h')
        {
            var indicator_top_pos = ((this.container.offset().top + this.container.height()) - this.indicator.height());
            var indicator_left_pos = (this.container.width() - this.indicator.width()) / 2;
            this.indicator.css({ top: indicator_top_pos, left: indicator_left_pos });
        }
        else
        {
            var indicator_top_pos = (this.container.height() - this.indicator.height()) / 2;
            var indicator_left_pos = (this.container.offset().left + this.container.width()) - 20;
            this.indicator.css({ top: indicator_top_pos, left: indicator_left_pos });
        }

        // Add the current styles to everything:
        $(this.cards[0]).addClass('current');
        this.indicator.items[0].addClass('current');

        // Hook up the drag events:
        var mouse_start_x = 0;
        var mouse_end_x   = 0;
        var mouse_start_y = 0;
        var mouse_end_y   = 0;
        var direction_x   = null;
        var direction_y   = null;
        var next_index    = 0;

        this.container.mousedown(function(e) {
            mouse_start_x = e.pageX;
            mouse_start_y = e.pageY;
        });
        this.container.mouseup(function(e) {
            mouse_end_x = e.pageX;
            mouse_end_y = e.pageY;

            alert(self.container.attr('id'));

            if(mouse_end_x > mouse_start_x) { direction_x = 'right'; }
            if(mouse_end_x < mouse_start_x) { direction_x = 'left'; }
            if(mouse_end_y > mouse_start_y) { direction_y = 'down'; }
            if(mouse_end_y < mouse_start_y) { direction_y = 'up'; }

            switch(self.direction)
            {
                case 'v':
                    if(direction_y == 'down') { next_index = (self.current_card == 0) ? 0 : self.current_card - 1; }
                    if(direction_y == 'up')   { next_index = (self.current_card == (self.no_cards - 1)) ? self.current_card : self.current_card + 1; }
                    break;

                case 'h':
                default:
                    if(direction_x == 'right') { next_index = (self.current_card == (self.no_cards - 1)) ? self.current_card : self.current_card + 1; }
                    if(direction_x == 'left')  { next_index = (self.current_card == 0) ? 0 : self.current_card - 1; }
                    break;
            }
            self.setCard(next_index);
        });

        // No need to return `this`, that's what constructor functions do by default
    }

    // Our various member functions, we'll assign them to the prototype below

    // Function to check if we're on the last card:
    function Carousel$onLastCard() {
        return (this.current_card == (this.indicator.items.length - 1)) ? true : false;
    }

    // Function to check if we're on the first card:
    function Carousel$onFirstCard() {
        return (this.current_card == 0) ? true : false;
    }

    function Carousel$setCard(index) {
        // If the index matches the current one, don't do anything:
        if(index == this.current_card)
        {
            return;
        }
        else
        {
            // Calculate the left position we need to move:
            var new_left_pos = this.card_width * index;
            this.card_container.css({ left: -new_left_pos });
            this.indicator.items[this.current_card].removeClass('current');
            this.indicator.items[index].addClass('current');
            this.current_card = index;
            return true;
        }
    }

    // Fill in the prototype that will be assigned to all objects created
    // via `new Carousel`:

    Carousel.prototype.onLastCard = Carousel$onLastCard;
    Carousel.prototype.onFirstCard = Carousel$onFirstCard;
    Carousel.prototype.setCard = Carousel$setCard;

    // Return our constructor out of the scoping function to be assigned
    // to the public var    
    return Carousel;

})();

А затем используйте:

$(function(){
    $('.carousel').each(function() { new Carousel($(this)); });
});

Опять же, вышеизложенное не означает, что оно идеально, сделано ипосыпанный.Он должен продемонстрировать, как вы переформулируете Carousel как функцию-конструктор и настраиваете функции на ее прототипе, чтобы они были назначены экземплярам, ​​созданным с помощью new Carousel.Там будет некоторая отладка требуется.Я рад видеть, что вы уже решаете проблему this в обработчиках событий (через вашу переменную self в том, что раньше было init и теперь является функцией Carousel).

Возможно, полезное чтение:

  • Anonymouses anonymous - объясняет, почему я использовал вышеописанную функцию scoping и реальные именованные функции
  • Простые, эффективные Supercalls в JavaScript - обсуждение создания функций конструктора (я назвал их "классами", но я действительно не должен был, я хотел обновить статью) и некоторые утилиты для созданияэто проще, а также включает иерархии, если они вам нужны
1 голос
/ 02 ноября 2011

При переборе элементов div карусели каждый раз создайте новый объект Carousel:

$(function(){
    $('.carousel').each(function() { new Carousel.init($(this)); });
});

См. Также http://jsfiddle.net/4nbYR/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...