从 VueJS 中的组件模板打开 Vuetify 对话框

Open a Vuetify dialog from a component template in VueJS

我正在使用 VueJS Vuetify framework,我需要从另一个模板打开一个对话框 - 作为组件模板导入。单击 Menu 按钮App.vue 中的 按钮,模态窗口应打开。 这是我的设置:

  • App.vue = 带菜单按钮的导航模板
  • Modal.vue = 模态模板,在 main.js
  • 中作为全局模板导入

main.js

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

Modal.vue 模板:

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

如何打开对话框?

在您的 App.vue template 中添加这个

<modal></model>

它将使用 v-btnv-dialog

呈现您当前的 Modal.vue 模板

现在它里面会有一个 button - Open Dialog 当你点击那个模式时会打开。

您可以使用自定义事件和 event bus for non parent-child communication 打开对话框。

如果您的应用程序变得有点复杂,我建议您使用 Vuex for state management


事件总线解决方案:

在您的 main.js 或在一个新文件中创建并导出一个新的 Vue 实例:

export const bus = new Vue()

app.vue 中导入 bus 并发出事件:

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

modal.vue中同样导入总线并监听创建的钩子中的事件:

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

不需要事件总线并且v-model

更新:

当我第一次回答这个问题时,我将我的答案作为“变通方法”发布,因为当时感觉它并不完全“正确”并且我是 Vue.js 的新手。我想使用 v-model 指令打开或关闭对话框,但无法到达那里。一段时间后,我发现 how to do this in the docs,使用 输入事件 值 属性,这就是我的想法应该在没有事件总线的情况下完成。

父组件:

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

子组件(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>

原回答:

我能够在不需要全局事件总线的情况下解决这个问题。

我使用了计算 属性 和 getter 和 setter。由于 Vue 会警告您直接改变父 属性,因此在 setter 中我只是向父

发出了一个事件。

代码如下:

父组件:

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

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

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

子组件(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>

There are many ways to do it such is Vuex,Event Bus,Props with which you can manage whether the modal have to open or to close.I will show you my favourite way using the .sync modifier:

首先我会简化你的问题(代码部分)

父组件

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

子(对话框)组件

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

我发现最简单的方法是:

在组件的 data() 中,return 一个属性,比方说,对话框。

包含组件时,可以设置对组件标签的引用。例如:

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

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

然后,在我的组件中,我设置了一个方法:

        open: function () {
            var vm = this;

            vm.dialog = true;
        }

最后,我可以从父级调用它,使用:

  editar(item)
  {
      var vm = this;

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

简单的最小工作示例

codepen

value 属性作为 value 传递给 v-dialog 组件,并在您想要关闭它时从子对话框发出 input 事件:

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

并将 v-model 添加到您的父级

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

所以没有自定义事件总线,没有 data,没有 watch,没有 computed

我更喜欢用这个:

DialogConfirm.vue

<template>
  <v-dialog :value="visible" max-width="450">
    <v-card>
      <v-card-title v-text="title" />
      <v-card-text v-text="message" />
      <v-card-actions v-if="visible">
        <template v-for="action in value">
          <v-spacer :key="action.label" v-if="typeof action == 'string'" />
          <v-btn
            v-else
            text
            :key="action.label"
            v-text="action.label"
            @click="doAction(action.action)"
            :color="action.color"
          />
        </template>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component';
import { Prop, Watch } from 'vue-property-decorator';

@Component
export default class DialogConfirm extends Vue {

  @Prop({ type: String, default: "Confirm" })
  title: string

  @Prop({ type: String, default: "Are you sure?" })
  message: string

  @Prop({ type: Array, default: undefined })
  value: { label: string, action: () => boolean, color: string }[]

  get visible() {
    return Array.isArray(this.value) && this.value.length > 0
  }

  doAction(action: () => boolean) {
    if ('undefined' == typeof action || action() !== false) {
      this.$emit('input', null)
    }
  }
}
</script>

用法示例

/** Disable AP Mode */
  setApMode(enable: boolean) {
    const action = () => {
      Api.get('wifi', {
        params: {
          ap: enable
        }
      }).then(response => this.$store.dispatch('status'))
    }
    if (enable == true) {
      // No confirmation
      return action();
    }
    this.dialogTitle = 'Are you sure?'
    this.dialogMessage = "you may lost connection to this device.";
    this.dialogActions = [
      {
        label: 'Cancel',
        color: 'success'
      },
      'spacer',
      {
        label: "OK, Disable it",
        color: "error",
        action
      }
    ]
  }

methods: {
  openDialog(e) {
    this.dialog = true;
  }
},

这个适合我