如何使用 vuetify 的选项卡而不是按钮触发 vuetify 对话框

How to trigger vuetify dialog with vuetify's tab instead of a button

我正在尝试使用 vuetify 的选项卡触发 vuetify 对话框。我不确定如何实现。我有两个组件,Tabs.vue 和 Dialog.vue。

来自 vuetify,Tabs.vue 组件是:

<template>
  <v-card>
    <v-tabs
      v-model="tab"
      background-color="deep-purple accent-4"
      centered
      dark
      icons-and-text
    >
      <v-tabs-slider></v-tabs-slider>

      <v-tab href="#tab-1">
        Recents
        <v-icon>mdi-phone</v-icon>
      </v-tab>

      <v-tab href="#tab-2">
        Favorites
        <v-icon>mdi-heart</v-icon>
      </v-tab>

      <v-tab href="#tab-3">
        Nearby
        <v-icon>mdi-account-box</v-icon>
      </v-tab>
    </v-tabs>

    <v-tabs-items v-model="tab">
      <v-tab-item
        v-for="i in 3"
        :key="i"
        :value="'tab-' + i"
      >
        <v-card flat>
          <v-card-text>{{ text }}</v-card-text>
        </v-card>
      </v-tab-item>
    </v-tabs-items>
  </v-card>
</template>

对话框组件是:

<template>
  <v-row justify="center">
    <v-dialog
      v-model="dialog"
      persistent
      max-width="600px"
    >
      <template v-slot:activator="{ on, attrs }">
        <v-btn
          color="primary"
          dark
          v-bind="attrs"
          v-on="on"
        >
          Open Dialog
        </v-btn>
      </template>
      <v-card>
        <v-card-title>
          <span class="headline">User Profile</span>
        </v-card-title>
        <v-card-text>
          <v-container>
            <v-row>
              <v-col
                cols="12"
                sm="6"
                md="4"
              >
                <v-text-field
                  label="Legal first name*"
                  required
                ></v-text-field>
              </v-col>
              <v-col
                cols="12"
                sm="6"
                md="4"
              >
                <v-text-field
                  label="Legal middle name"
                  hint="example of helper text only on focus"
                ></v-text-field>
              </v-col>
              <v-col
                cols="12"
                sm="6"
                md="4"
              >
                <v-text-field
                  label="Legal last name*"
                  hint="example of persistent helper text"
                  persistent-hint
                  required
                ></v-text-field>
              </v-col>
              <v-col cols="12">
                <v-text-field
                  label="Email*"
                  required
                ></v-text-field>
              </v-col>
              <v-col cols="12">
                <v-text-field
                  label="Password*"
                  type="password"
                  required
                ></v-text-field>
              </v-col>
              <v-col
                cols="12"
                sm="6"
              >
                <v-select
                  :items="['0-17', '18-29', '30-54', '54+']"
                  label="Age*"
                  required
                ></v-select>
              </v-col>
              <v-col
                cols="12"
                sm="6"
              >
                <v-autocomplete
                  :items="['Skiing', 'Ice hockey', 'Soccer', 'Basketball', 'Hockey', 'Reading', 'Writing', 'Coding', 'Basejump']"
                  label="Interests"
                  multiple
                ></v-autocomplete>
              </v-col>
            </v-row>
          </v-container>
          <small>*indicates required field</small>
        </v-card-text>
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn
            color="blue darken-1"
            text
            @click="dialog = false"
          >
            Close
          </v-btn>
          <v-btn
            color="blue darken-1"
            text
            @click="dialog = false"
          >
            Save
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-row>
</template>

请注意,我直接从 vuetify 复制了每个组件。如您所见,为了触发对话框,vuetify 给出了使用 Dialog.vue 组件内的按钮的示例,我将再次粘贴下面的那部分代码:

<template v-slot:activator="{ on, attrs }">
    <v-btn
      color="primary"
      dark
      v-bind="attrs"
      v-on="on"
    >
      Open Dialog
    </v-btn>
 </template>

它正在使用 v-slot:activator 触发对话框。但是,我不确定如何使用 Tabs.vue 中的选项卡之一来触发来自 Dialogs.vue 的对话框。谢谢

我为你做了一个CodeSandbox。如果这是你想要的,我会在之后解释我所做的。 Check here

好的...

首先让我们检查一下您的结构。 您将 Dialog.vue 包装在它自己的组件中,这意味着您现在需要从外部切换 Dialog On/Off 机制,即 parent(Tabs.vue).

Tabs.vue

<template>
  <v-card>
    <v-tabs
      background-color="deep-purple accent-4"
      centered
      dark
      icons-and-text
    >
      <v-tabs-slider></v-tabs-slider>
      <v-tab href="#tab-1" @change="toggleDialog('recents')">
        Recents
        <v-icon>mdi-phone</v-icon>
      </v-tab>

      <v-tab href="#tab-2" @change="toggleDialog('favorites')">
        Favorites
        <v-icon>mdi-heart</v-icon>
      </v-tab>

      <v-tab href="#tab-3" @change="toggleDialog('nearby')">
        Nearby
        <v-icon>mdi-account-box</v-icon>
      </v-tab>
    </v-tabs>

    <v-tabs-items>
      <v-tab-item v-for="i in 3" :key="i" :value="'tab-' + i">
        <v-card flat>
          <v-card-text>{{ text }}</v-card-text>
        </v-card>
      </v-tab-item>
    </v-tabs-items>
    <Dialog <--------------------------- ADDING component Dialog.vue
      :show-dialog="dialog" <----------- PROP the On/Off logic
      :tab-controll="tabControll" <----- PROP the "which tab is selected"
      @close-dialog="dialog = false" <-- TOGGLE Off on "close" button
      @save-dialog="dialog = false" <--- TOGGLE Off on "save" button
    />
  </v-card>
</template>

<script>
import Dialog from "@/components/Dialog";
export default {
  components: {
    Dialog,
  },
  data() {
    return {
      tab: 0,
      dialog: false, <--------- CONTROLLS the On/Off mechanism inside Dialog.vue
      tabControll: "None Tab",<- CONTROLLS which tab is selected in Dialog.vue
      text: "some text i guess",
    };
  },
  methods: {
    toggleDialog(tab) {
      this.tabControll = tab;
      this.dialog = true;
    },
  },
};
</script>

<style>
</style>

每个 v-tab 都有自己的 changed 事件,这就是为什么你需要在每个 v-tab.

上收听它
<v-tabs
      background-color="deep-purple accent-4"
      centered
      dark
      icons-and-text
    >
      <v-tabs-slider></v-tabs-slider>
      <v-tab href="#tab-1" @change="toggleDialog('recents')"> <------- @change
        Recents
        <v-icon>mdi-phone</v-icon>
      </v-tab>

      <v-tab href="#tab-2" @change="toggleDialog('favorites')"> <------- @change
        Favorites
        <v-icon>mdi-heart</v-icon>
      </v-tab>

      <v-tab href="#tab-3" @change="toggleDialog('nearby')"> <------- @change
        Nearby
        <v-icon>mdi-account-box</v-icon>
      </v-tab>
    </v-tabs>

现在让我们看看 toggleDialog 函数

methods: {
    toggleDialog(tab) {
      this.tabControll = tab;
      this.dialog = true;
    },
  },

它什么都不做,然后将 data 中的 dialog 切换为 true 并设置 tabControllDialog.vue 知道单击了哪个选项卡。

Dialog.vue

现在我们准备Dialog.vue来处理外部控制的行为。

<template>
  <v-row justify="center">
    <v-dialog v-model="dialog" persistent max-width="600px"> <--------- HERE
      <v-card>
        <v-card-title>
          <span class="headline">User Profile - {{ tabControll }}</span>
        </v-card-title>
        <v-card-text>
          <v-container>
            <v-row>
              <v-col cols="12" sm="6" md="4">
                <v-text-field label="Legal first name*" required></v-text-field>
              </v-col>
              <v-col cols="12" sm="6" md="4">
                <v-text-field
                  label="Legal middle name"
                  hint="example of helper text only on focus"
                ></v-text-field>
              </v-col>
              <v-col cols="12" sm="6" md="4">
                <v-text-field
                  label="Legal last name*"
                  hint="example of persistent helper text"
                  persistent-hint
                  required
                ></v-text-field>
              </v-col>
              <v-col cols="12">
                <v-text-field label="Email*" required></v-text-field>
              </v-col>
              <v-col cols="12">
                <v-text-field
                  label="Password*"
                  type="password"
                  required
                ></v-text-field>
              </v-col>
              <v-col cols="12" sm="6">
                <v-select
                  :items="['0-17', '18-29', '30-54', '54+']"
                  label="Age*"
                  required
                ></v-select>
              </v-col>
              <v-col cols="12" sm="6">
                <v-autocomplete
                  :items="[
                    'Skiing',
                    'Ice hockey',
                    'Soccer',
                    'Basketball',
                    'Hockey',
                    'Reading',
                    'Writing',
                    'Coding',
                    'Basejump',
                  ]"
                  label="Interests"
                  multiple
                ></v-autocomplete>
              </v-col>
            </v-row>
          </v-container>
          <small>*indicates required field</small>
        </v-card-text>
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn color="blue darken-1" text @click="$emit('close-dialog')">
            Close
          </v-btn>
          <v-btn color="blue darken-1" text @click="$emit('save-dialog')">
            Save
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-row>
</template>
<script>
export default {
  data() {
    return {
      dialog: this.showDialog,
    };
  },
  watch: {
    showDialog: function () {
      this.dialog = this.showDialog;
    },
  },
  props: {
    showDialog: {
      type: Boolean,
      default: false,
    },
    tabControll: {
      type: String,
      default: "none",
    },
  },
};
</script>

<style>
</style>

我们保持一致并且我们不在我们的 v-model="dialog" 中使用 showDialog 道具,否则我们会收到警告,我们在不知道 parent 的情况下改变道具(Tabs.vue)

<v-dialog v-model="dialog" persistent max-width="600px">

相反,我们将传入的 prop 数据绑定到我们的 dialog 内部数据

data() {
    return {
      dialog: this.showDialog,
    };
  },

现在我们不从外部改变道具,我们只是复制从 Tabs.vue

处理的对话框的状态

如果您现在单击选项卡,事件会将此 showDialog 切换为 true,这会将数据中的 dialog 也更改为 true 并显示对话框。

到目前为止一切顺利...现在我们需要再次关闭对话框的功能。

正如我多次说过的,改变道具是一件坏事,我们触发 $emit 并告诉 Tabs.vue 再次关闭对话框。

<v-btn color="blue darken-1" text @click="$emit('close-dialog')">
  Close
</v-btn>
<v-btn color="blue darken-1" text @click="$emit('save-dialog')">
  Save
</v-btn>

回到

Tabs.vue

我们监听那些自定义事件并切换 dialog = false 就在这里

<Dialog
      :show-dialog="dialog"
      :tab-controll="tabControll"
      @close-dialog="dialog = false" <-- TOGGLE Off on "close" button
      @save-dialog="dialog = false" <--- TOGGLE Off on "save" button
    />