web-dev-qa-db-fra.com

Vue.js Changer les accessoires

Je suis un peu confus sur la façon de changer les propriétés à l'intérieur des composants, disons que j'ai le composant suivant:

{
    props: {
        visible: {
            type: Boolean,
            default: true
        }
    },
    methods: {
         hide() {
              this.visible = false;
         }
    }
} 

Bien que cela fonctionne, cela donnerait l'avertissement suivant: 

Évitez de muter directement un accessoire, car la valeur sera écrasée à chaque nouvelle restitution du composant parent. Utilisez plutôt une propriété data ou calculée en fonction de la valeur de l'accessoire. Prop étant muté: "visible" (trouvé dans le composant)

Maintenant, je me demande quel est le meilleur moyen de gérer cela. De toute évidence, la propriété visible est transmise lors de la création du composant dans le DOM: <Foo :visible="false"></Foo>

13
woutr_be

Référencer le code dans votre violon

D'une manière ou d'une autre, vous devriez choisir un lieu pour que l'État vive, pas deux. Je ne sais pas s'il est plus approprié de l'indiquer uniquement dans la variable Alert ou simplement dans sa parenté, mais vous devriez en choisir une.

Comment décider où vit l'Etat

Est-ce que le parent ou un composant frère dépend de l'état?

  • Oui: il devrait alors être dans le parent (ou dans une gestion d’état externe)
  • Non: alors il est plus facile de l'avoir dans l'état du composant lui-même
  • Un peu les deux: voir ci-dessous

Dans de rares cas, vous voudrez peut-être une combinaison. Peut-être voudrez-vous donner aux parents et à l’enfant la possibilité de cacher l’enfant. Ensuite, vous devriez avoir l'état dans parent et enfant (vous n'avez donc pas à modifier les accessoires de l'enfant dans l'enfant).

Par exemple, enfant peut être visible si: visible && state_visible, où visible provient d'accessoires et reflète une valeur dans l'état du parent, et state_visible correspond à l'état de l'enfant.

Je ne sais pas si c'est le comportement que vous souhaitez, mais voici un violon . J'imagine que vous voulez simplement appeler la toggleAlert du composant parent lorsque vous cliquez sur l'enfant.

11
ArneHugo

Après avoir lu vos derniers commentaires, il semble que vous ayez le souci de disposer de la logique pour afficher/masquer les alertes sur le parent. Par conséquent, je suggérerais ce qui suit:

parent

# template
<alert :alert-visible="alertVisible"></alert>

# script
data () {
  alertVisible: false,
  ...
},
...

Ensuite, sur l'alerte enfant, vous observerez la valeur de l'accessoire et déplacerez toute la logique dans l'alerte:

enfant (alerte)

# script
data: {
  visible: false,
  ...
},
methods: {
  hide () {
    this.visible = false
  },
  show () {
    this.visible = true
  },
  ...
},
props: [
  'alertVisible',
],
watch: {
  alertVisible () {
    if (this.alertVisible && !this.visible) this.show()
    else if (!this.alertVisible && this.visible) this.hide()
  },
  ...
},
...
4
GuyC

Si l'accessoire n'est utile que pour ce composant enfant, donnez à l'enfant une variable prop telle que initialVisible et une variable data telle que mutableVisible et dans le crochet created (appelé lorsque la structure de données du composant est assemblée), simplement this.mutableVisible = this.initialVisible

Si l'accessoire est partagé par d'autres enfants du composant parent, vous devez en faire la variable data du parent pour qu'il soit disponible pour tous les enfants. Ensuite, dans l’enfant, this.$emit('visibleChanged', currentVisible) pour avertir le parent de changer visible. Dans le modèle parent, utilisez <ThatChild ... :visibleChanged="setVisible" ...>. Consultez le guide: http://vuejs.org/v2/guide/components.html

3
PanJunjie潘俊杰

Pour aider qui que ce soit, je faisais face au même problème. Je viens de changer ma variable qui se trouvait dans v-model = "" de props array en data. Rappelez-vous la différence entre les accessoires et les données. Dans mon cas, ce n’était pas un problème si vous le changiez, vous devriez peser votre décision.

Par exemple.:

<v-dialog v-model="dialog" fullscreen hide-overlay transition="dialog-bottom-transition">

Avant:

export default {
    data: function () {
        return {
            any-vars: false
        }
    },
    props: {
            dialog: false,
            notifications: false,
            sound: false,
            widgets: false
        },
    methods: {
        open: function () {
            var vm = this;

            vm.dialog = true;
        }
    }
}

Après:

export default {
    data: function () {
        return {
            dialog: false
        }
    },
    props: {
            notifications: false,
            sound: false,
            widgets: false
        },
    methods: {
        open: function () {
            var vm = this;

            vm.dialog = true;
        }
    }
}
2
Marco

Selon le composant Vue.js doc

Lorsque la propriété parent est mise à jour, elle se répercute sur l'enfant, mais pas l'inverse. Alors, comment pouvons-nous communiquer avec le parent lorsque quelque chose se passe? C’est là que le système d’événements personnalisé de Vue entre en jeu.

Utilisez $emit('my-event) de l'enfant pour envoyer un événement au parent. Recevez l'événement sur la déclaration enfant à l'intérieur du parent avec v-on:my-event (ou @my-event). 

Exemple de travail:

// child

Vue.component('child', {
  template: '<div><p>Child</p> <button @click="hide">Hide</button></div>',
  methods: {
    hide () {
      this.$emit('child-hide-event')
    }
  },
})

// parent

new Vue({
  el: '#app',
  data: {
    childVisible: true
  },
  methods: {
    childHide () {
      this.childVisible = false
    },
    childShow () {
      this.childVisible = true
    }
  }
})
.box {
  border: solid 1px grey;
  padding: 16px;
}
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="app" class="box">
  <p>Parent | childVisible: {{ childVisible }}</p>
  <button @click="childHide">Hide</button>
  <button @click="childShow">Show</button>
  <p> </p>
  <child @child-hide-event="childHide" v-if="childVisible" class="box"></child>
</div>

0
François Romain

Peut-être que cela ressemble à du piratage et viole le concept d'une source de données unique, mais son travail) Cette solution crée une variable proxy locale et hérite des données des accessoires. Prochain travail avec la variable proxy.

Vue.component("vote", {
    data: function() {
        return {
            like_: this.like,
            dislike_: this.dislike,
        }
    },

    props: {
        like: {
            type: [String, Number],
            default: 0
        },
        dislike: {
            type: [String, Number],
            default: 0
        },
        item: {
            type: Object
        }
    },

    template: '<div class="tm-voteing"><span class="tm-vote tm-vote-like" @click="onVote(item, \'like\')"><span class="fa tm-icon"></span><span class="tm-vote-count">{{like_}}</span></span><span class="tm-vote tm-vote-dislike" @click="onVote(item, \'dislike\')"><span class="fa tm-icon"></span><span class="tm-vote-count">{{dislike_}}</span></span></div>',

    methods: {
        onVote: function(data, action) {
            var $this = this;
            // instead of jquery ajax can be axios or vue-resource
            $.ajax({
                method: "POST",
                url: "/api/vote/vote",
                data: {id: data.id, action: action},
                success: function(response) {
                    if(response.status === "insert") {
                        $this[action + "_"] = Number($this[action + "_"]) + 1;
                    } else {
                        $this[action + "_"] = Number($this[action + "_"]) - 1;
                    }
                },
                error: function(response) {
                    console.error(response);
                }
            });
        }
    }
});

utiliser le composant et passer les accessoires

<vote :like="item.vote_like" :dislike="item.vote_dislike" :item="item"></vote>
0
Vitaliy