Maison > interface Web > js tutoriel > Comment utiliser Sortable dans Vue

Comment utiliser Sortable dans Vue

php中世界最好的语言
Libérer: 2018-05-26 15:36:00
original
2693 Les gens l'ont consulté

Cette fois, je vais vous montrer comment utiliser Sortable dans Vue, et quelles sont les précautions à prendre pour utiliser Sortable dans Vue. Ce qui suit est un cas pratique, jetons un coup d'œil.

J'ai précédemment développé un système de gestion backend utilisant la bibliothèque de composants Vue et Element-UI. J'ai rencontré un problème très intéressant et j'aimerais le partager avec vous.

La scène est comme ceci. Sur une page d'affichage de liste, j'ai utilisé le composant table d'Element-UI. La nouvelle exigence est de prendre en charge le tri par glisser-déposer basé sur la table d'origine. Cependant, le composant d'origine lui-même ne prend pas en charge le tri par glisser-déposer, et comme il est directement introduit depuis Element-UI, il n'est pas pratique de modifier son code source, la seule méthode réalisable est donc d'exploiter directement le DOM.

La méthode spécifique consiste à effectuer de vraies opérations DOM sur this.$el dans la fonction de cycle de vie montée, à écouter une série d'événements de glisser, à déplacer le DOM dans le rappel d'événement et à mettre à jour les données.

Il existe de nombreux événements HTML5 Drag, qui sont similaires aux événements Touch. Vous pouvez également les implémenter manuellement, mais ici, je suis paresseux et j'utilise une bibliothèque open source Sortable et je la transmets directement.$el. Écoutez le rappel encapsulé et, selon le modèle de développement de Vue, mettez à jour les données Data réelles dans le rappel DOM mobile pour maintenir la cohérence entre les données et le DOM.

Si vous pensez que c'est fini ici, vous vous trompez totalement. Tôt ou tard, vous devrez rembourser la paresse que vous avez volée. . . J'ai trouvé cette solution merveilleuse, mais dès que j'ai voulu la déboguer, un phénomène étrange s'est produit : après que A et B aient été glissés et échangés, B et A ont été à nouveau échangés comme par magie ! Que se passe-t-il? Il semble qu'il n'y ait aucun problème avec notre opération.Une fois le vrai DOM déplacé, nous déplaçons également les données correspondantes.L'ordre du tableau de données et l'ordre du DOM rendu doivent être cohérents.

Quel est le problème ? Rappelons le principe d'implémentation de Vue. Avant Vue2.0, la liaison bidirectionnelle était réalisée via l'injection et le suivi des dépendances DefineProperty. Pour l'instruction de tableau v-for, si une clé unique est spécifiée, la différence entre les éléments du tableau sera calculée via un algorithme Diff efficace et des opérations de mouvement ou de suppression minimales seront effectuées. Après l'introduction de Virtual Dom après Vue 2.0, l'algorithme Dom Diff de l'élément Children est en fait similaire au premier. La seule différence est qu'avant 2.0, Diff ciblait directement l'objet tableau de l'instruction v-for, tandis qu'après 2.0, il ciblait le Virtual Dom. L'algorithme DOM Diff ne sera pas décrit en détail ici. L'algorithme de comparaison dom virtuel est expliqué plus clairement ici

Supposons que notre tableau d'éléments de liste soit

['A',' B', 'C', 'D']

Le nœud DOM rendu est

[$A,$B,$C,$D]

Alors la structure correspondante de Virtual Dom est

[{elm:$A,data:'A'},
{elm:$ B, data :'B'},
{elm:$C,data:'C'},
{elm:$D,data:'D'}]

Supposons qu'après le tri par glisser-déposer, le vrai DOM devient

[$B,$A,$C,$D]

À cette fois, nous avons seulement Le vrai DOM a été manipulé et sa position a été adaptée, mais la structure du Virtual Dom n'a pas changé. Il est toujours

[{elm:$A,data:'. A'},
{elm :$B,data:'B'},
{elm:$C,data:'C'},
{elm:$D,data:'D' }]

À ce moment-là, nous trions également les éléments de la liste en fonction du vrai DOM et devenons

['B','A',' C','D']

À l'heure actuelle, selon l'algorithme Diff, le Patch calculé est Les deux premiers éléments de VNode sont des nœuds du même type, ils le sont donc. mis à jour directement, c'est-à-dire que le nœud $A est mis à jour en $B et le nœud $B est mis à jour en $A, le vrai DOM est redevenu

[$A,$B, $C,$D]

, donc après avoir glissé, un autre Pour les problèmes mis à jour une fois par l'algorithme du Patch, le chemin de l'opération peut être simplement compris comme

glisser et déplacer le vrai DOM -> faire fonctionner le tableau de données -> L'algorithme de patch met ensuite à jour le vrai DOM

Cause première

La cause première est l'incohérence entre DOM virtuel et DOM réel.

Donc, avant Vue2.0, comme Virtual DOM n'a pas été introduit, ce problème n'existait pas.

Lorsque vous utilisez le framework Vue, essayez d'éviter de manipuler directement le DOM

Solution

1. Marquez de manière unique chaque VNode en définissant la clé. C'est également la manière dont Vue recommande d'utiliser l'instruction v-for. Parce que la méthode sameVnode sera appelée pour juger si deux VNodes sont du même type, la priorité est de juger si la clé est la même

function sameVnode (a, b) {
 return (
  a.key === b.key &&
  a.tag === b.tag &&
  a.isComment === b.isComment &&
  isDef(a.data) === isDef(b.data) &&
  sameInputType(a, b)
 )
}
Copier après la connexion

2. Parce que la raison fondamentale est que le vrai DOM et Les VNode sont incohérents, vous pouvez donc déplacer le vrai DOM en faisant glisser Le fonctionnement du DOM est restauré, c'est-à-dire que dans la fonction de rappel, [$B, $A, $C, $D] est restauré en [$A, $B , $C, $D], et l'opération du DOM est renvoyée à Vue

Faites glisser et déplacez le vrai DOM ->Restaurer l'opération de déplacement-> Manipuler le tableau de données-> l'algorithme met ensuite à jour le vrai DOM

Le code est le suivant

var app = new Vue({
    el: '#app', 
    mounted:function(){
      var $ul = this.$el.querySelector('#ul')
      var that = this
      new Sortable($ul, {
        onUpdate:function(event){
          var newIndex = event.newIndex,
            oldIndex = event.oldIndex
            $li = $ul.children[newIndex],
            $oldLi = $ul.children[oldIndex]
          // 先删除移动的节点
          $ul.removeChild($li)  
          // 再插入移动的节点到原有节点,还原了移动的操作
          if(newIndex > oldIndex) {
            $ul.insertBefore($li,$oldLi)
          } else {
            $ul.insertBefore($li,$oldLi.nextSibling)
          }
          // 更新items数组
          var item = that.items.splice(oldIndex,1)
          that.items.splice(newIndex,0,item[0])
          // 下一个tick就会走patch更新
        }
      })
    },
    data:function() {
      return {
        message: 'Hello Vue!',
        items:[{
          key:'1',
          name:'1'
        },{
          key:'2',
          name:'2'
        },{
          key:'3',
          name:'3'
        },{
          key:'4',
          name:'4'
        }]
      }
    },
    watch:{
      items:function(){
        console.log(this.items.map(item => item.name))
      }
    }
  })
Copier après la connexion

Solution violente ! Sans mise à jour du correctif, effectuez un nouveau rendu directement via les paramètres v-if. Bien sûr, ce n'est pas recommandé de faire cela, je donne juste cette idée~

    mounted:function(){
      var $ul = this.$el.querySelector('#ul')
      var that = this
      var updateFunc = function(event){
        var newIndex = event.newIndex,
          oldIndex = event.oldIndex
        var item = that.items.splice(oldIndex,1)
        that.items.splice(newIndex,0,item[0])

        // 暴力重新渲染!
        that.reRender = false
        // 借助nextTick和v-if重新渲染
        that.$nextTick(function(){
          that.reRender = true
          that.$nextTick(function(){
            // 重新渲染之后,重新进行Sortable绑定
            new Sortable(that.$el.querySelector('#ul'), {
              onUpdate:updateFunc
            })
          })
        })
      }
      new Sortable($ul, {
        onUpdate:updateFunc
      })
    },
Copier après la connexion

Donc, lorsque nous utilisons habituellement le framework, nous devons également comprendre le principe de mise en œuvre du framework, sinon nous rencontrerons certains situations difficiles. Pas moyen de commencer~

Je pense que vous maîtrisez la méthode après avoir lu le cas dans cet article. Pour des informations plus intéressantes, veuillez prêter attention aux autres articles connexes sur le site Web chinois de php !

Lecture recommandée :

Comment faire fonctionner nodejs pour restituer les ressources de la page via l'écriture de réponse

Comment faire fonctionner nodejs à utiliser websocket

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
vue
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal