2016-02-05 4 views
4

У меня есть основной Vue.js объект:Update порядок массива в Vue.js после изменения DOM

var playlist = new Vue({ 
    el : '#playlist', 
    data : { 
     entries : [ 
      { title : 'Oh No' }, 
      { title : 'Let it Out' }, 
      { title : 'That\'s Right' }, 
      { title : 'Jump on Stage' }, 
      { title : 'This is the Remix' } 
     ] 
    } 
}); 

HTML:

<div id="playlist"> 
    <div v-for="entry in entries"> 
     {{ entry.title }} 
    </div> 
</div> 

Я также с помощью перетаскивания библиотеки (Dragula) чтобы позволить пользователям перегруппировать div #playlist.

Однако, после того, как пользователь перегруппирует плейлист с помощью dragula, это изменение не отражается на playlist.entries Vue, только в DOM.

Я подключился к событиям dragula, чтобы определить начальный индекс и конечный индекс перемещенного элемента. Каков правильный способ обновления объекта Vue, чтобы отразить новый порядок?

Fiddle: https://jsfiddle.net/cxx77kco/5/

ответ

6

Vue в v-for не отслеживает изменения в DOM-элементов, которые она создает. Итак, вам нужно обновить модель, когда dragula уведомит вас об изменении. Вот рабочая скрипку: https://jsfiddle.net/hsnvweov/

var playlist = new Vue({ 
    el : '#playlist', 
    data : { 
     entries : [ 
      { title : 'Oh No' }, 
      { title : 'Let it Out' }, 
      { title : 'That\'s Right' }, 
      { title : 'Jump on Stage' }, 
      { title : 'This is the Remix' } 
     ] 
    }, 
    ready: function() { 
     var self = this; 
     var from = null; 
     var drake = dragula([document.querySelector('#playlist')]); 

     drake.on('drag', function(element, source) { 
      var index = [].indexOf.call(element.parentNode.children, element); 
      console.log('drag from', index, element, source); 
      from = index; 
     }) 

     drake.on('drop', function(element, target, source, sibling) { 
      var index = [].indexOf.call(element.parentNode.children, element) 
      console.log('drop to', index, element, target, source, sibling); 

      self.entries.splice(index, 0, self.entries.splice(from, 1)[0]); 

      console.log('Vue thinks order is:', playlist.entries.map(e => e.title).join(', ') 
      ); 
     }) 
    } 
}); 
2

Я создал директиву Vue, которая делает именно эту работу.

Это работает точно так же, как об-за директивы и добавить возможность перетаскивания и падение в синхронизации с основным массивом ViewModel:

example

Syntaxe:

<div v-dragable-for="element in list">{{element.name}}</div> 

Пример: fiddle1, fiddle2

Реестр Github: Vue.Dragable.For

2

vue-dragula делает это автоматически и проще в использовании. https://github.com/Astray-git/vue-dragula

+1

Спасибо! Похоже, этого не было, когда я задал вопрос. Рад видеть, как кто-то сделал это в lib. –