web-dev-qa-db-fra.com

Ouvrir une boîte de dialogue Vuetify à partir d'un modèle de composant dans VueJS

J'utilise le VueJS cadre Vuetify et je dois ouvrir une boîte de dialogue - importée en tant que modèle de composant - à partir d'un autre modèle. Une fois le bouton Menu dans App.vue eu cliqué, le modal devrait s'ouvrir. Voici ma configuration:

  • App.vue = modèle de navigation avec bouton Menu
  • Modal.vue = Modèle modal, importé en tant que global dans main.js

main.js

import Modal from './components/Modal.vue'
Vue.component('modal', Modal)

Modal.vue Template:

<template>
  <v-layout row justify-center>
    <v-btn color="primary" dark @click.native.stop="dialog = true">Open Dialog</v-btn>
    <v-dialog v-model="dialog" max-width="290">
      <v-card>
        <v-card-title class="headline">Use Google's location service?</v-card-title>
        <v-card-text>Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running.</v-card-text>
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn color="green darken-1" flat="flat" @click.native="dialog = false">Disagree</v-btn>
          <v-btn color="green darken-1" flat="flat" @click.native="dialog = false">Agree</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-layout>
</template>
<script>
  export default {
    data () {
      return {
        dialog: false
      }
    }
  }
</script>

Comment ouvrir le dialogue?

22
Tom

Vous pouvez ouvrir la boîte de dialogue à l'aide d'événements personnalisés et à l'aide d'un bus d'événements pour les communications non parent-enfant .

Si votre application devient un peu plus complexe, je vous recommande d'utiliser Vuex pour la gestion d'état .


Solution de bus d'événements:

Dans votre main.js ou dans un nouveau fichier, créez et exportez une nouvelle instance Vue:

export const bus = new Vue()

Dans app.vue , importez le bus et émettez l'événement:

<template>
  <div>
    <button @click.prevent="openMyDialog()">my button</button>
  </div>
</template>

<script>
  import {bus} from '../main' // import the bus from main.js or new file
  export default {
    methods: {
      openMyDialog () {
        bus.$emit('dialog', true) // emit the event to the bus
      }
    }
  }
</script>

Dans modal.vue importez également le bus et écoutez l'événement dans le hook créé:

<script>
  import {bus} from '../main'    
  export default {
    created () {
      var vm = this
      bus.$on('dialog', function (value) {
        vm.dialog = value
      })
    }
  }
</script>
10
Soleno

Aucun bus d'événement requis et modèle v

Mise à jour:

Quand j'ai d'abord répondu à cela, j'ai posté ma réponse en tant que "solution de contournement", car elle ne me semblait pas complètement "correcte" à l'époque et que j'étais nouveau dans Vue.js. Je voulais ouvrir ou fermer le dialogue en utilisant une directive v-model , mais je n'y suis pas parvenu. Après un certain temps, j'ai trouvé comment faire cela dans la documentation , en utilisant l'événement d'entrée et le value value , et voici comment je pense que cela devrait être fait sans bus d'événements.

Composant parent:

<template>
   <v-btn color="accent" large @click.stop="showScheduleForm=true">    
   <ScheduleForm v-model="showScheduleForm" />
</template>

<script>
import ScheduleForm from '~/components/ScheduleForm'

export default {
  data () {
    return {
      showScheduleForm: false
    }
  },
  components: {
    ScheduleForm
  }
}
</script>

Composant enfant (ScheduleForm):

<template>
<v-dialog v-model="show" max-width="500px">
  <v-card>
    <v-card-actions>
      <v-btn color="primary" flat @click.stop="show=false">Close</v-btn>
    </v-card-actions>
  </v-card>
</v-dialog>
</template>

<script>
export default {
  props: {
     value: Boolean
  },
  computed: {
    show: {
      get () {
        return this.value
      },
      set (value) {
         this.$emit('input', value)
      }
    }
  }
}
</script>

Réponse originale:

J'ai pu contourner ce problème sans avoir besoin d'un bus d'événements mondial.

J'ai utilisé une propriété calculée avec un getter ET un setter. Depuis Vue vous avertit de la mutation directe de la propriété parent, dans l'émetteur, j'ai simplement émis un événement au parent.

Voici le code:

Composant parent:

<template>
   <v-btn color="accent" large @click.stop="showScheduleForm=true">    
   <ScheduleForm :visible="showScheduleForm" @close="showScheduleForm=false" />
</template>

<script>
import ScheduleForm from '~/components/ScheduleForm'

export default {
  data () {
    return {
      showScheduleForm: false
    }
  },
  components: {
    ScheduleForm
  }
}
</script>

Composant enfant (ScheduleForm):

<template>
<v-dialog v-model="show" max-width="500px">
  <v-card>
    <v-card-actions>
      <v-btn color="primary" flat @click.stop="show=false">Close</v-btn>
    </v-card-actions>
  </v-card>
</v-dialog>
</template>

<script>
export default {
  props: ['visible'],
  computed: {
    show: {
      get () {
        return this.visible
      },
      set (value) {
        if (!value) {
          this.$emit('close')
        }
      }
    }
  }
}
</script>
53

Il y a plusieurs façons de le faire, telles que Vuex, Event Bus, Props avec lequel vous pouvez gérer si le modal doit s'ouvrir ou se fermer. Je vais vous montrer mon moyen préféré en utilisant le modificateur .sync:

Je vais d'abord vous simplifier la question (la partie code)

composant parent

<template>
   <div>
     <button @click="dialog=true">Open Dialog</button>
     <Child :dialog.sync="dialog" />
   </div>
</template>

<script>
import Child from './Child.vue'
export default {
    components: {
      Child
    },
    data: {
      return {
        dialog: false
      }
   }
}
</script>

composant enfant (dialogue)

<template>
  <v-layout row justify-center>
    <v-dialog v-model="dialog" persistent max-width="290">
      <v-card>
        <v-card-title class="headline">Use Google's location service?</v-card-title>
        <v-card-text>Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running.</v-card-text>
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn color="green darken-1" flat @click.native="close">Close</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-layout>
</template>

<script>

  export default {
    props: {
        dialog: {
        default: false
      }
    },
    methods: {
        close() {
        this.$emit('update:dialog', false)
      }
    }
  }

</script>
10
roli roli

Exemple de travail minimal simple

codepen

Passez value prop comme value à v-dialog composant et à partir de la boîte de dialogue enfant, émettez un événement input à chaque fois que vous souhaitez le fermer:

//CustomDialog.vue
<v-dialog :value="value" @input="$emit('input')">
  <v-btn color="red" @click.native="$emit('input')">Close</v-btn>
</v-dialog>
...
props:['value']

et ajoutez v-model à votre parent

//Parent.vue
<custom-dialog v-model="dialog">

Donc, pas de bus d'événements personnalisé, pas de data, ni de watch, ni de computed.

3
Traxo

La façon la plus simple que j'ai trouvée de le faire est:

dans data () du composant, retourne un attribut, disons dialogue.

Lorsque vous incluez un composant, vous pouvez définir une référence à votre balise de composant. Par exemple.:

import Edit from '../payment/edit.vue';

<edit ref="edit_reference"></edit>

Ensuite, dans ma composante, j'ai défini une méthode:

        open: function () {
            var vm = this;

            vm.dialog = true;
        }

Enfin, je peux l'appeler de parent en utilisant:

  editar(item)
  {
      var vm = this;

      vm.$refs.edit_reference.open();
  }
2
Marco

dans votre App.vuetemplate ajoutez ceci

<modal></model>

il rendra votre modèle actuel Modal.vue avec v-btn et v-dialog

maintenant, à l'intérieur, il y aura un button - Open Dialog lorsque vous cliquerez sur ce modal qui s'ouvrira.

1
Hardik Satasiya