Магистраль прекращает прослушивание событий после запуска события n раз

#backbone.js #websocket

#backbone.js #websocket

Вопрос:

Я пишу встроенный в браузер пульт дистанционного управления для демона mpd music, используя неофициальную библиотеку mpdjs и backbone.js с помощью библиотеки backbone.CollectionView. Данные передаются между браузером и сервером через websockets.

Следующий блок кода управляет запуском события:

 App.Views.PlayerView = Backbone.View.extend
  template: _.template(JST.player())
  events:
    'click .song': 'changeSong'

  changeSong: (e) ->
    classList = e.currentTarget.classList
    classList.remove('song')
    classList.remove('ui-sortable-handle')

    songId = classList[0]
    socket.send("play-song:#{songId.split('-')[1]}")

  render: () ->
    emp = @model.toJSON()
    html = @template(emp)
    html = $(html).addClass("song song-#{emp.id}")[0]
    @$el.append(html)

App.Views.PlaylistView = new Backbone.CollectionView
  el: $('.queue')
  selectable: true
  collection: App.CurrentPlaylist
  modelView: App.Views.PlayerView
  

Это соответствующие модели и коллекции:

 App.Models.Song = Backbone.Model.extend
  defaults:
    track: ''
    title: ''
    artist: ''
    album: ''
    length: ''

App.Collections.Playlist = Backbone.Collection.extend
  model: App.Models.Song
App.CurrentPlaylist = new App.Collections.Playlist
  

Когда приложение запускается и подключается к WebSocketServer, следующий код заполняет следующую разметку:

  // this is wrapped in socket.onmessage, and is only called once
  parseTime = (time) ->
    min = Math.floor(parseInt(time, 10) / 60)
    sec = Math.floor(parseInt(time, 10) % 60)
    if sec < 10
      sec = "0#{sec}"
    "#{min}:#{sec}"

  for key, value of data.playlist
    song = new App.Models.Song(
      id: value.Id
      track: value.Track.split('/')[0]
      title: value.Title
      artist: value.Artist
      album: value.Album
      length: parseTime(value.Time)
    )
    App.CurrentPlaylist.add(song)

  App.Views.PlaylistView.render()

// this is the markup it spits out
<table class="queue pure-table collection-list selectable" tabindex="0">
  <div data-model-cid="c3">
    <tr class="song song-1">
      <td>3</td>
      <td>Reykjavik Blues</td>
      <td>Inf</td>
      <td>The Go Round</td>
      <td>2:06</td>
      </tr>
  </div>
  <div data-model-cid="c4">
    <tr class="song song-2">
      <td>5</td>
      <td>Wasting Time</td>
      <td>Inf</td>
      <td>The Go Round</td>
      <td>2:30</td>
    </tr>
  </div>
</table>
  

Когда ‘play-song-2’ отправляется на сервер, вызывается следующая функция. ‘2’ анализируется из ‘play-song-2’, поэтому эта функция работает правильно.

 function playSong(ws, songId) {
  mpdConnection.sendCommand('playid '   songId, function(err, msg) {
    if (err) throw err;

    // this is a helper function that takes the plain text response
    // and organizes it into a javascript object
    msg = msgToObject(msg);  
    msg.type = 'song-update';
    ws.send(JSON.stringify(msg));
  });
}
  

Проблема, с которой я сталкиваюсь, однако, заключается в том, что при загрузке страницы она changeSong(e) запускается практически мгновенно после .song нажатия. Однако, если на странице n композиций, страница перестает прослушивать события после n нажатий.

Обновление: похоже, я случайно исправил эту проблему с помощью нескольких изменений макета. Я изменил представление так, чтобы вместо вставки div при рендеринге вставлялся tr:

 App.Views.PlayerView = Backbone.View.extend
  tagName: 'tr'
  template: _.template(JST.player())
  events:
    'click': 'changeSong'
  

и я убрал .выбор класса песни, позволяющий прослушивать событие при всех щелчках мыши. С селектором исходное, нарушенное поведение все еще сохраняется, но без него проигрыватель работает очень хорошо. Однако я все еще не уверен, почему это на самом деле сработало, поэтому я предлагаю вознаграждение любому, кто может это объяснить.

Ответ №1:

Это ваше мнение

 App.Views.PlayerView = Backbone.View.extend
  events:
    'click .song': 'changeSong'

  changeSong: (e) ->
    classList = e.currentTarget.classList
    classList.remove('song')
    # your logic
  

Теперь, согласно вашему events хэшу, он говорит, что всякий раз, когда щелкается элемент с именем класса song , затем выполняйте метод changeSong . Но внутри changeSong вы удаляете classname song . Следовательно, обработчик события запускается только один раз! потому что после его запуска имя класса song удаляется.

Итак, если у вас есть примерно 4 песни, щелкните четыре из них один раз, а затем, после того, как ни один из щелчков не запустит changeSong метод. Проясняет ли это ситуацию?