2011-11-02 84 views
3

這是一個棘手的問題。我正在構建一個Carousel視圖,該視圖在使用jQuery的加載時間中得到了關注。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(),但他們都沒有工作)。任何幫助最感激地收到。

+1

謝謝@TJCrowder ,我已經添加了完整的jQuery代碼t這個問題也是。 – BenM

回答

5

你打電話Carousel.init的方式,init函數內this永遠是Carousel   —也就是說,只有一個。這就是爲什麼你只看到它被應用到最後。

我想看看返工Carousel是一個構造函數(你使用new的種類)。 @Boo剛剛在Carousel.init之前拋出了new,這是一個很好的開始,但創建的對象將不具有您在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的問題(通過您在init中的self變量,現在是Carousel函數)。

一些可能有用的閱讀:

  • Anonymouses anonymous - 解釋了爲什麼我使用的範圍界定功能和真實的,命名功能上面
  • Simple, Efficient Supercalls in JavaScript - 創建構造函數的討論(I」我稱它們爲「類」,但我真的不應該這樣做,我一直有意更新這篇文章)以及一些實用程序,以便使它更容易,以及在需要時啓用層次結構
+0

感謝您在T.J.Crowder提供的寶貴幫助 - 這是一個絕妙的解決方案,只需稍加修改,我就能讓它工作得很好。我也非常喜歡閱讀你分享的兩篇文章。 – BenM

+0

@BenM:好的交易,很高興幫助!哦,這個可能也很有用:[神話方法](http://blog.niftysnippets.org/2008/03/mythical-methods.html)。 (這有助於解釋爲什麼'this'本來就是'Carousel'。)最好的, –

1

當在轉盤上的div迭代,創建一個新的輪播對象每次:

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

參見http://jsfiddle.net/4nbYR/

+0

謝謝@Boo。每次創建一個新的Carousel對象現在會產生以下錯誤:即使其他所有東西似乎都是相關聯的,Object [object Object]也沒有方法'setCard'。有小費嗎? – BenM

+0

@BenM:這是因爲'new Carousel.init'創建的對象有一個空白的原型(因爲'Carousel.init.prototype'上沒有任何東西),但是你的代碼假設它會有你放在'旋轉木馬'對象。你真正想要的是一個正確的構造函數,我已經做了一個快速(未經測試)的例子,它可能在我的答案中看起來像。 –

相關問題