4
votes

v-on click, ajouter un gestionnaire uniquement si la condition a été remplie

Après quelques recherches, la suggestion suivante de M. Evan You a été trouvée: https://github.com/vuejs/vue/issues/7349#issuecomment- 354937350

Donc, sans aucune hésitation, je l'ai essayé:

Modèle de composant

DataModel: {
  mainSectionA: {
    sections: {
      sectionA: {
        sections: {
          elementA: { values: { ... } },     
          elementB: { values: { ... } }
        }
        values: { ... }
      }
      sectionB: {
        elementA: { values: { ... } },
        elementB: { values: { ... } }
      }
    },
    values: { ... }
  },
  mainSectionB: {
    sections: {
      elementA: { values: { ... } },
      elementB: { values: { ... } },  
      elementC: { values: { ... } },
      ... elements
    },
    values: { ... }
  }
}

JS Logic

[Vue warn]: Invalid handler for event "click": got null

Mais pour le cas décrit, il en résulte une erreur lors du rendu:

<script>
export default {
  name: `product-section`,
  props: [`section`, `sectionName`, `depth`],
  methods: {
    toggleSectionElements() {
      ... magic 
    }
  },
  computed: {
    dataType() {
      if (this.$props.section.sections || this.$props.depth === 0) {
        return `section`
      } else {
        return `element`
      }
    }
  }
}
</script>

Quelqu'un peut-il s'il vous plaît suggérer ce qui a été mal fait? : réflexion:

Mettre à jour
À quoi ressemble le Modèle de données :

<template>
  <div v-on='{ click: dataType === `section` ? toggleSectionElements : null }'>
    ... magic 
  </div>
<template>


0 commentaires

3 Réponses :


1
votes

ici:

click: dataType === `section` ? toggleSectionElements : ()=>{}

dans le cas différent, vous passez null, mais la valeur au clic attend une fonction. vous pouvez essayer une fonction emptry:

click: dataType === `section` ? toggleSectionElements : null


1 commentaires

Le fait de devoir utiliser des éléments aussi originaux montre l'absence de fonctionnalité dans Vue.



3
votes

Modifiez-le simplement comme suit et cela fonctionnera

v-on="condition ? { mouseover } : {}"

ou, si votre gestionnaire s'appelle mouseover

v-on="condition ? { mouseover: handler } : {}"


0 commentaires

4
votes

Au lieu de polluer votre modèle avec une logique ternaire, vous devriez plutôt effectuer la vérification à l'intérieur du gestionnaire de clics. Cela rend non seulement votre modèle plus lisible, mais facilite également la maintenance du code puisque toute la logique a été abstraite et déléguée au rappel du gestionnaire d'événements.

Solution rapide

Par conséquent, la solution rapide consiste en fait à assurez-vous que toggleSectionElements () ne fonctionnera que lorsqu'un dataType correct est présent. Ceci peut être réalisé en utilisant une clause de garde:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <my-collection />
</div>

<script type="text/x-template" id="my-collection-component">
  <div>
    <component
      v-for="(item, i) in collection"
      v-bind:key="i"
      v-bind:is="componentToUse(item.dataType)"
      v-bind:itemData="item" />
  </div>
</script>

<script type="text/x-template" id="my-section-component">
  <div @click="toggle" class="box">
    <h1>{{ itemData.dataType }}</h1>
    <p>{{ itemData.description }}</p>
    <p>Clicking on me will invoke a section-specific logic</p>
  </div>
</script>

<script type="text/x-template" id="my-element-component">
  <div class="box">
    <h1>{{ itemData.dataType }}</h1>
    <p>{{ itemData.description }}</p>
    <p>Clicking on me will do nothing</p>
  </div>
</script>

Encore mieux, c'est que si des gestionnaires séparés doivent être attribués à chaque dataType : vous pouvez alors créer une fonction d'usine à cet effet:

.box {
  border: 1px solid #999;
  cursor: pointer;
  margin: 10px;
  padding: 10px;
}

.box:hover {
  background-color: #eee;
}

Suggestion: utiliser des composants atomiques

Puisqu'il peut être coûteux de lier des gestionnaires d'événements de clic à des éléments qui finissent par ne rien faire, vous pouvez également décomposer votre composant pour qu'il soit plus atomique. L'élément de collection sera responsable de recevoir un tableau de "section" ou "élément", et chaque "section" / "élément" aura son propre composant, quelque chose comme ceci:

  • Vous avez un composant de collection, disons , qui contient tous les composants "section" et "élément"
  • Le composant
  • "section" utilisera le composant
  • Le composant
  • "element" utilisera le composant

C'est là que VueJS devient vraiment puissant: vous pouvez utiliser composant dynamique dans pour déterminer quel composant utiliser en fonction du dataType rencontré.

Cela se fait en exécutant un v-for à travers la collection, puis en utilisant v-bind: is = "..." pour déterminer si un élément de collection spécifique doit utiliser "section" ou "élément". Je comprends que cela va probablement sortir du cadre de votre question initiale, mais c'est une conception intéressante à prendre en compte:

const collectionComponent = Vue.component('my-collection', {
  template: '#my-collection-component',
  data: function() {
    return {
      collection: [{
        dataType: 'section',
        description: 'Hello I am section 1'
      }, {
        dataType: 'element',
        description: 'Hello I am element 1'
      }, {
        dataType: 'section',
        description: 'Hello I am section 2'
      }, {
        dataType: 'element',
        description: 'Hello I am element 2'
      }]
    }
  },
  methods: {
    componentToUse(dataType) {
      return 'my-' + dataType;
    }
  }
});

const sectionComponent = Vue.component('my-section', {
  template: '#my-section-component',
  props: ['itemData'],
  methods: {
    toggle() {
      console.log('Doing some magic.');
    }
  }
});

const elementComponent = Vue.component('my-element', {
  template: '#my-element-component',
  props: ['itemData']
});

new Vue({
  el: '#app'
});
methods: {
  // This is just a factory function
  toggleElements() {
    switch (this.dataType()) {
      case 'section':
        return this.toggleSectionElements;
      case 'element':
        // Something else...
    }
  },
  toggleSectionElements() {
    // Magic for section element
  }
}
toggleSectionElements() {
  // Guard clause to prevent further code execution
  if (this.dataType() !== 'section')
    return;

  // Magic here
}


3 commentaires

Merci pour votre suggestion, Terry. Je pensais à votre suggestion comme approche initiale. Je n'ai pas posté ici mais ce modèle est une sorte de composant récursif. Où à la fin, il finit par rendre environ 10 sections et 60 éléments.


Les sections devraient avoir l'auditeur, contrairement aux éléments, trouvez-vous raisonnable de vérifier réellement dans l'auditeur, plutôt que de ne pas tout ajouter? (en fait des curiosités)


@volna C'est une préoccupation appropriée. Une meilleure solution est d'avoir en fait des composants atomiques : dans ce cas, vous aurez deux composants séparés: un à consommer par "section" et un autre à consommer par "élément". Le composant "section" peut avoir l'événement click lié à celui-ci, alors que "l'élément" n'est pas obligé de le faire.