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

问题描述 投票:0回答:7

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

  • App.vue = 带菜单按钮的导航模板
  • Modal.vue = Modal 模板,在 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>

如何打开对话框?

javascript vuejs2 vue-component vuetify.js
7个回答
192
投票

无需事件总线和 v 模型

更新:

当我第一次回答这个问题时,我将我的答案作为“解决方法”发布,因为当时感觉并不完全“正确”,而且我对 Vue.js 还很陌生。我想使用 v-model 指令打开或关闭对话框,但我无法到达那里。一段时间后,我发现如何在文档中执行此操作,使用输入事件值属性,这是我认为应该如何在没有事件总线的情况下完成此操作。

父组件:

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

23
投票

有很多方法可以做到这一点,例如 Vuex、Event Bus、Props,您可以使用它们来管理模式是否必须打开或关闭。我将向您展示我最喜欢的使用

.sync
修饰符的方法:

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

父组件

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

23
投票

简单的最小工作示例

Vue.use(Vuetify);
Vue.component("custom-dialog", {
  template: `
    <v-dialog :value="value" @input="$emit('input')">
      <v-card>         
        <v-btn color="red" @click.native="$emit('input')">Close</v-btn>
      </v-card>
    </v-dialog>`,
  props: ["value"]
});

var vm = new Vue({
  el: "#app",
  data() {
    return {
      dialog: false
    };
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuetify.min.js"></script>
<div id="app">
  <v-app>
    <v-btn @click="dialog = true">Open</v-btn>
    <custom-dialog v-model="dialog" />
  </v-app>
</div>

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


14
投票

您可以使用自定义事件打开对话框,并使用事件总线进行非父子通信

如果您的应用程序变得更复杂一点,我建议您使用 Vuex 进行状态管理


事件总线解决方案:

在您的 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>

4
投票

我发现最简单的方法是:

在组件的 data() 中,返回一个属性,比如说对话框。

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

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();
  }

1
投票

我更喜欢用这个:

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


-1
投票
methods: {
  openDialog(e) {
    this.dialog = true;
  }
},

这个对我有用

© www.soinside.com 2019 - 2024. All rights reserved.