Maison  >  Article  >  interface Web  >  Problème de détection de changement de tableau dans vue

Problème de détection de changement de tableau dans vue

php中世界最好的语言
php中世界最好的语言original
2018-04-17 15:36:221608parcourir

Cette fois, je vais vous présenter le problème de la détection des changements de tableau dans Vue. Quelles sont les précautions pour la détection des changements de tableau dans Vue. Voici un cas pratique, jetons un coup d'œil.

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>vue</title>
 <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script>
 <style>
  li:hover {
   cursor: pointer;
  }
 </style>
</head>
<body>
 <p class="wrap">
  <ul>
   <li v-for="item,index in items" v-on:click="handle(index)">
    <span>{{item.name}}</span>
    <span>{{numbers[index]}}</span>
   </li>
  </ul>
 </p>
 <script>
  var vm = new Vue({
   el: ".wrap",
   data: {
    numbers: [],
    items: [
     {name: 'jjj'},
     {name: 'kkk'},
     {name: 'lll'},
    ]
   },
   methods: {
    handle: function (index) {
     // WHY: 更新数据,view层未渲染,但通过console这个数组可以发现数据确实更新了
      if (typeof(this.numbers[index]) === "undefined" ) {
       this.numbers[index] = 1;
      } else {
       this.numbers[index]++;
      }
    }
   }
  });
 </script>
</body>
</html>

Le but de l'implémentation ici est très clair --- j'espère détecter si li existe en cliquant dessus. Bien sûr, il n'existe pas, j'ai donc défini la valeur sur 1. Si je clique à nouveau dessus, laisse le nombre s'accumuler.

Mais le problème qui se pose est le suivant : après avoir cliqué, le numéro n'est pas mis à jour dans la couche de vue, et grâce à l'impression de la console, on constate que les données sont bien mises à jour, mais la couche de vue ne les détecte pas à temps. Et ce que je pensais, c'est : puisque Vue implémente la liaison de données bidirectionnelle, pourquoi n'est-elle pas mise à jour dans la couche de vue après les modifications de la couche de modèle ? Tout d'abord, j'ai examiné s'il s'agissait d'un problème de tableau, j'ai donc testé l'exemple suivant :

Exemple 2

À ce moment-là, lorsque j'ai testé à nouveau, j'ai découvert que lorsque la couche de modèle change ici, la couche de vue peut être mise à jour de manière rapide et efficace.
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>vue</title>
 <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script>
 <style>
  li:hover {
   cursor: pointer;
  }
 </style>
</head>
<body>
 <p class="wrap">
  <ul>
   <li v-for="item,index in items" v-on:click="handle(index)">
    <span>{{item.name}}</span>
    <span>{{numbers[index]}}</span>
   </li>
  </ul>
 </p>
 <script>
  var vm = new Vue({
   el: ".wrap",
   data: {
    numbers: [],
    items: [
     {name: 'jjj'},
     {name: 'kkk'},
     {name: 'lll'},
    ]
   },
   methods: {
    handle: function (index) {
     // 不是数组,这里更新数据就可以直接在view层渲染
     this.items[index].name += " success";
    }
   }
  });
 </script>
</body>
</html>

La phrase la plus importante est --- si l'objet est réactif, assurez-vous que l'attribut

est également réactif après sa création et déclenche une mise à jour de la vue. Cette méthode est principalement utilisée pour éviter que Vue ne puisse pas le faire. détecter l'attribut, des restrictions ont été ajoutées. Alors, dans quelles circonstances Vue peut-il ne pas détecter que des attributs ont été ajoutés ? D'après le lien de référence, nous avons vu une bonne explication dans le document --- Principe réactif en profondeur

Tout d’abord, nous devons comprendre comment Vue implémente la liaison bidirectionnelle des données !

Passez un objet

JavaScript

normal à l'option data de l'instance Vue. Vue parcourra toutes les propriétés de cet objet et l'utilisera. Object.defineProperty convertit toutes ces propriétés en getters/setters. Object.defineProperty est uniquement ES5 prend en charge mais ne peut pas caler les fonctionnalités, c'est pourquoi Vue ne prend pas en charge les navigateurs IE8 et inférieurs. Supplément de connaissances :

Les propriétés d'accesseur ne contiennent pas de valeurs de données ; elles contiennent une paire de fonctions getter et setter (ces deux fonctions ne sont pas obligatoires). Lorsque la propriété accesseur est lue, la fonction getter est appelée, qui est chargée de renvoyer une valeur valide ; lorsque la propriété accesseur est écrite, la fonction setter est appelée et la nouvelle valeur est transmise. Cette fonction est chargée de décider comment traiter les données.

Les propriétés de l'accesseur ne peuvent pas être définies directement et doivent être définies à l'aide de Object.defineProperty().

Voici un exemple :

Cet exemple devrait fournir une bonne compréhension des propriétés des accesseurs.
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>vue</title>
</head>
<body>
 <script>
  var book={
    _year:2004,
    edition:1
  };
  Object.defineProperty(book,"year",{
    get:function(){
      return this._year;
    },
    set:function(newValue){
      if(newValue>2004){
        this._year=newValue;
        this.edition+=newValue-2004;
      }
    }
  });
  console.log(book.year); // 2004 在读取访问器属性时会调用get函数
  book.year=2005; // 在给访问器属性赋值时会调用set函数
  console.log(book.edition); // 2
 </script>
</body>
</html>

Par conséquent, lorsque la valeur de l'attribut d'accesseur sous l'objet change (Vue convertira les attributs en attributs d'accesseur, comme mentionné précédemment), alors la fonction set sera appelée, puis Vue pourra suivre les modifications via cette fonction set et appeler les fonctions associées. pour mettre à jour la vue.

Chaque instance de composant a un objet d'instance d'observateur correspondant, qui enregistre les propriétés en tant que dépendances pendant le processus de rendu du composant. Plus tard, lorsque le setter de la dépendance est appelé, l'observateur sera invité à recalculer, entraînant la mise à jour de ses composants associés. Autrement dit, pendant le processus de rendu, la fonction getter de l'attribut d'objet sera appelée, puis la fonction getter informera l'objet eau de le déclarer comme dépendance. Après la dépendance, si l'attribut d'objet change, la fonction setter le fera. sera appelé pour avertir l'observateur, et l'observateur restituera le composant pour terminer la mise à jour.

D'ACCORD! Maintenant que nous connaissons le principe, nous pouvons mieux comprendre pourquoi le problème de matrice précédent s'est produit !

Problèmes de détection des modifications

Reçu par les limitations des navigateurs JavaScript modernes, il s'agit en fait principalement de Object.observe() La prise en charge de la méthode n'est pas bonne et Vue ne peut pas détecter l'ajout ou la suppression d'objets. Cependant, Vue effectue le processus de conversion setter/getter sur la propriété lors de l'initialisation de l'instance, la propriété doit donc être sur l'objet depuis le début pour que Vue puisse la convertir.

所以对于前面的例子就不能理解了 --- 数组中index都可以看做是属性,当我们添加属性并赋值时,Vue并不能检测到对象中属性的添加或者删除,但是其的确是添加或删除了,故我们可以通过console看到变化,所以就没有办法做到响应式; 而在第二个例子中,我们是在已有的属性的基础上进行修改的,这些属性是在最开始就被Vue初始化实例时执行了setter/getter的转化过程,所以说他们的修改是有效的,model的数据可以实时的在view层中得到相应。

补充知识: 什么是 Object.observe() ?

在介绍之前,不得不残忍的说,尽管这个方法可以在某些浏览器上运行,但事实是这个方法已经废弃!

概述: 此方法用于异步地监视一个对象的修改。当对象的属性被修改时,方法的回调函数会提供一个有序的修改流,然而这个接口已经从各大浏览器移除,可以使用通用的proxy 对象。      

方法:

Object.observe(obj, callback[, acceptList])

其中obj就是被监控的对象, callback是一个回调函数,其中的参数包括changes和acceptList,

changes一个数组,其中包含的每一个对象代表一个修改行为。每个修改行为的对象包含:

  • name: 被修改的属性名称。

  • object: 修改后该对象的值。

  • type: 表示对该对象做了何种类型的修改,可能的值为"add", "update", or "delete"。

  • oldValue: 对象修改前的值。该值只在"update"与"delete"有效。

acceptList在给定对象上给定回调中要监视的变化类型列表。如果省略, ["add", "update", "delete", "reconfigure", "setPrototype", "preventExtensions"] 将会被使用。

var obj = {
 foo: 0,
 bar: 1
};
Object.observe(obj, function(changes) {
 console.log(changes);
});
obj.baz = 2;
// [{name: 'baz', object: <obj>, type: 'add'}]
obj.foo = 'hello';
// [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}]
delete obj.baz;
// [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

layer前端组件图片显示功能

web前端必看4本开发书籍

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