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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48035310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:00:04  来源:igfitidea点击:

Open a Vuetify dialog from a component template in VueJS

javascriptvuejs2vue-componentvuetify.js

提问by Tom

I'm using the VueJS Vuetify frameworkand I need to open a dialog - that gets imported as a component template - from another template. Once the Menubuttonin App.vuegot clicked, the Modal should open. Here is my setup:

我正在使用 VueJS Vuetify 框架,我需要从另一个模板打开一个对话框 - 作为组件模板导入。一旦菜单按钮App.vue得到了点击,莫代尔应该打开。这是我的设置:

  • App.vue = navigation template with Menu button
  • Modal.vue = Modal template, imported as global in main.js
  • App.vue = 带有菜单按钮的导航模板
  • Modal.vue = 模态模板,在 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?

如何打开对话框?

采纳答案by Soleno

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.jsor in a new file create and export a new Vue instance :

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

export const bus = new Vue()

export const bus = new Vue()

In app.vueimport the busand 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.vuealso 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>

回答by Matheus Dal'Pizzol

No event bus needed and v-model

不需要事件总线和 v 模型

Update:

更新:

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. I wanted to open or close the dialog by using a v-modeldirective, but I couldn't get there. After a time I found how to do this in the docs, using the input eventand the value property, and here's how I think it should be done without an event bus.

当我第一次回答这个问题时,我将我的答案发布为“解决方法”,因为当时感觉并不完全“正确”,而且我是 Vue.js 的新手。我想通过使用v-model指令打开或关闭对话框,但我无法到达那里。一段时间后,我在文档中找到了如何使用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>

Original answer:

原答案:

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. Since Vue warns you about mutating the parent property directly, in the setter I simply emitted an event to the parent.

我使用了一个带有 getter 和 setter 的计算属性。由于 Vue 会警告您直接改变 parent 属性,因此在 setter 中,我只是向父级发出了一个事件。

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>

回答by roli roli

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 .syncmodifier:

有很多方法可以做到这一点,例如 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>

回答by Traxo

Simple minimal working example

简单的最小工作示例

codepen

代码笔

Pass valueprop as valueto v-dialogcomponent, and from child dialog emit inputevent whenever you want to close it:

valueprop传递valuev-dialog组件,并input在您想要关闭它时从子对话框发出事件:

//CustomDialog.vue
<v-dialog :value="value" @input="$emit('input')">
  <v-btn color="red" @click.native="$emit('input')">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

回答by Marco

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. E.g.:

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

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

回答by Hardik Satasiya

within your App.vuetemplateadd this

在你App.vuetemplate添加这个

<modal></model>

it will render your current Modal.vuetemplate with v-btnand v-dialog

它将Modal.vue使用v-btn和呈现您当前的模板v-dialog

now inside it there will be one button- Open Dialogwhen you click on that modal will open.

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

回答by Mochamad Arifin

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