Maison  >  Article  >  interface Web  >  Utiliser Vue+Triable

Utiliser Vue+Triable

php中世界最好的语言
php中世界最好的语言original
2018-06-11 10:54:242223parcourir

Cette fois, je vais vous présenter l'utilisation de Vue+Sortable et quelles sont les précautions d'utilisation de Vue+Sortable. 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'}]

En supposant qu'après le glisser-déposer tri, le vrai Le DOM devient

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

A cette époque nous avons seulement manipulé le vrai DOM et adapté son position, et La structure de Virtual Dom n'a pas changé, elle est toujours

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

En ce moment, nous changer les éléments de la liste en fonction du vrai DOM Après le tri, cela devient

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

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

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

Il y a donc un problème qui il est mis à jour par l'algorithme Patch après le glisser. Le chemin d'opération peut être simplement compris comme

Glisser et déposer pour déplacer le vrai DOM -> Manipuler le tableau de données -> 🎜>

La cause profonde

La cause profonde se situe entre le DOM virtuel et le DOM réel. Il y a une incohérence.

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 une 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)
 )
}

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-> 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))
      }
    }
  })

3. Résoudre la violence ! 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, mais 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
      })
    },

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. vers d'autres articles connexes sur le site Web PHP chinois !

Lecture recommandée :

Vue+Nuxt.js effectue un rendu côté serveur

Angular utilise l'analyse du code HMR

Utilisez vue pour créer une liste déroulante mobile

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!

Déclaration:
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