[英]Open a Vuetify dialog from a component template in VueJS
I'm using the VueJS Vuetify framework and I need to open a dialog - that gets imported as a component template - from another template.我正在使用 VueJS Vuetify 框架,我需要从另一个模板打开一个对话框 - 作为组件模板导入。 Once the Menu button in App.vue got clicked, the Modal should open.
一旦App.vue中的Menu按钮被点击,Modal 应该会打开。 Here is my setup:
这是我的设置:
main.js main.js
import Modal from './components/Modal.vue'
Vue.component('modal', Modal)
Modal.vue Template: 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>
How to open the dialog?如何打开对话框?
When I first answered this, I posted my answer as a "workaround", since it didn't felt completely "right" at the time and I was new to Vue.js.当我第一次回答这个问题时,我将我的答案发布为“解决方法”,因为当时感觉它并不完全“正确”,而且我是 Vue.js 的新手。 I wanted to open or close the dialog by using a v-model directive, but I couldn't get there.
我想使用v-model指令打开或关闭对话框,但我无法到达那里。 After some time I found how to do this in the docs , using the input event and the value property , and here's how I think it should be done without an event bus.
一段时间后,我在文档中找到了如何使用input 事件和value 属性来执行此操作,这就是我认为在没有事件总线的情况下应该如何完成的。
Parent component:父组件:
<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>
Child component (ScheduleForm):子组件(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>
I was able to work around this without the need for a global event bus.我能够在不需要全局事件总线的情况下解决这个问题。
I used a computed property with a getter AND a setter.我使用了一个带有 getter 和 setter 的计算属性。 Since Vue warns you about mutating the parent property directly, in the setter I simply emitted an event to the parent.
由于 Vue 会警告您直接更改父属性,因此在设置器中我只是向父级发出了一个事件。
Here's the code:这是代码:
Parent component:父组件:
<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>
Child component (ScheduleForm):子组件(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:有很多方法可以做到这一点,例如 Vuex、Event Bus、Props,您可以使用它们来管理模式是否必须打开或关闭。我将向您展示我最喜欢的使用
.sync
修饰符的方式:
First i will simplify you question(the code part)首先我会简化你的问题(代码部分)
Parent component父组件
<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>
Child(Dialog) Component子(对话框)组件
<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>
Pass value
prop as value
to v-dialog
component, and from child dialog emit input
event whenever you want to close it:将
value
prop 作为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']
and add v-model to your parent并将 v-model 添加到您的父级
//Parent.vue
<custom-dialog v-model="dialog">
So no custom event bus, no data
, no watch
, no computed
.所以没有自定义事件总线,没有
data
,没有watch
,没有computed
。
You can open the dialog using custom events and using an event bus for non parent-child communication .您可以使用自定义事件打开对话框,并使用事件总线进行非父子通信。
If your application gets a bit more complex I recommend you use Vuex for state management .如果您的应用程序变得有点复杂,我建议您使用Vuex 进行状态管理。
Event bus solution:事件总线解决方案:
In your main.js or in a new file create and export a new Vue instance :在您的main.js或新文件中创建并导出一个新的 Vue 实例:
export const bus = new Vue()
In app.vue import the bus
and emit the event:在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>
In modal.vue also import the bus and listen for the event in the created hook:在modal.vue 中还导入总线并在 created 钩子中监听事件:
<script>
import {bus} from '../main'
export default {
created () {
var vm = this
bus.$on('dialog', function (value) {
vm.dialog = value
})
}
}
</script>
The most simpler way I found to do it is:我发现最简单的方法是:
in data() of component, return a attribute, let's say, dialog.在组件的 data() 中,返回一个属性,比如说对话框。
When you include a component, you can set a reference to your component tag.包含组件时,可以设置对组件标记的引用。 Eg:
例如:
import Edit from '../payment/edit.vue';
<edit ref="edit_reference"></edit>
Then, inside my component, I have set a method:然后,在我的组件内部,我设置了一个方法:
open: function () {
var vm = this;
vm.dialog = true;
}
Finally, I can call it from parent, using:最后,我可以从父级调用它,使用:
editar(item)
{
var vm = this;
vm.$refs.edit_reference.open();
}
I prefer use this:我更喜欢使用这个:
DialogConfirm.vue 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>
Usage Example使用示例
/** 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
}
]
}
within your App.vue
template
add this在你的
App.vue
template
中添加这个
<modal></model>
it will render your current Modal.vue
template with v-btn
and v-dialog
它将使用
v-btn
和v-dialog
呈现您当前的Modal.vue
模板
now inside it there will be one button
- Open Dialog
when you click on that modal will open.现在里面会有一个
button
- 当您单击该模式时Open Dialog
将打开。
methods: {
openDialog(e) {
this.dialog = true;
}
},
This one works for me这个对我有用
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.