【问题标题】:want to use vuetify snackbar as a global custom component in vuejs想在 vuejs 中使用 vuetify 小吃吧作为全局自定义组件
【发布时间】:2020-10-29 14:31:33
【问题描述】:

我使用snackbar 在vuejs 中显示成功消息。我想做一个全局自定义的snackbar组件。

<template>
  <div name="snackbars">
    <v-snackbar
      v-model="snackbar"
      :color="color"
      :timeout="timeout"
      :top="'top'"
    >
      {{ text }}

      <template v-slot:action="{ attrs }">
        <v-btn dark text v-bind="attrs" @click="snackbar = false">
          Close
        </v-btn>
      </template>
    </v-snackbar>
  </div>
</template>

<script>
export default {
  props: {
    snackbar: {
      type: Boolean,
      required: true,
    },
    color: {
      type: String,
      required: false,
      default: "success",
    },
    timeout: {
      type: Number,
      required: false,
      default: 3000,
    },
    text: {
      type: String,
      required: true,
    },
  },
};
</script>

然后我将它作为一个组件导入到我的每个表单中。

<SnackBar :snackbar="snackbar" :color="color" :text="text" />

但我的问题是我不能在我的子组件中使用snackbar 作为道具。它显示了这个错误。

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "snackbar" 

我该如何解决这个问题。谁能帮帮我?

【问题讨论】:

  • 您的错误状态不在道具上使用 v-model。只需使用计算代理它并向父​​级发送更新

标签: vue.js vuetify.js


【解决方案1】:

我找到了一种使用 vuex 修复我的解决方案的方法。

    <template>
      <div name="snackbars">
        <v-snackbar v-model="show" :color="color" :timeout="timeout" :top="'top'">
          {{ text }}
    
          <template v-slot:action="{ attrs }">
            <v-btn dark text v-bind="attrs" @click="snackbar = false">
              Close
            </v-btn>
          </template>
        </v-snackbar>
      </div>
    </template>
    
    <script>
    export default {
      created() {
        this.$store.subscribe((mutation, state) => {
          if (mutation.type === "snackbar/SHOW_MESSAGE") {
            this.text = state.snackbar.text;
            this.color = state.snackbar.color;
            this.timeout = state.snackbar.timeout;
            this.show = true;
          }
        });
      },
      data() {
        return {
          show: false,
          color: "",
          text: "",
          timeout: 0,
        };
      },
    };
    </script>

在我的 vuex 模块中我是这样写的

    export default {
      namespaced: true,
      state: {
        text: "",
        color: "",
        timeout: "",
      },
      mutations: {
        SHOW_MESSAGE(state, payload) {
          state.text = payload.text;
          state.color = payload.color;
          state.timeout = payload.timeout;
        },
      },
      actions: {
        showSnack({ commit }, payload) {
          commit("SHOW_MESSAGE", payload);
        },
      },
    };

然后我将snackbar子组件导入我的父组件并像这样发送数据。

    ...mapActions("snackbar", ["showSnack"]),
    saveDetails() {
       this.showSnack({
            text: "Successfully Saved!",
            color: "success",
            timeout: 3500,
          });
     }

【讨论】:

  • 我认为您可以删除动作部分并直接在突变中执行,因为您没有任何副作用。
【解决方案2】:

我意识到这已经过时了,但感谢 google,我将添加我的解决方案。 我使用它,因为我没有看到将 vuex 用于小吃店的意义。需要做的工作更多。

创建一个名为 vtoast 的 vue 组件

<template>
  <v-snackbar
      :color="color"
      :timeout="timer"
      v-model="showSnackbar"
      bottom
      right
  >
    <v-icon left>{{icon}}</v-icon>{{message}}
  </v-snackbar>
</template>

<script>
export default {
  name: "vtoast",
  data() {
    return{
      showSnackbar: false,
      message: '',
      color: 'success',
      icon: 'mdi-check',
      timer: 3000
    }
  },
  methods:{
    show(data) {
      this.message = data.message || 'missing "message".'
      this.color = data.color || 'success'
      this.timer = data.timer || 3000
      this.icon = data.icon || 'mdi-check'
      this.showSnackbar = true
    }
  }
}
</script>

在主应用的根目录中的某处,添加以下内容。(我通常将我的放在 App.vue 中)

<template>
...
    <!-- toast -->
    <vtoast ref="vtoast"/>
...
</template>

<script>
import vtoast from '@/your/vtoast/directory/vtoast'
export default{
    name: 'App', //or whatever your root is
    components:{
        vtoast
    },
    mounted() {
      this.$root.vtoast = this.$refs.vtoast
    },
}
</script>

然后像这样访问它......

this.$root.vtoast.show()
this.$root.vtoast.show({message: 'Ahoy there!'})

【讨论】:

  • 非常有用,干净又简单!谢谢!
  • 嗨,我使用了你的方法,但它显示错误(this.$root.vtoast.show())
【解决方案3】:

另一种解决方案是使用带有 getter 和 setter 的计算值。

使用选项 api

<template>
  <v-snackbar v-model="show" :color="color">
    {{ message }}
    <template v-slot:action="{ attrs }">
      <v-btn text v-bind="attrs" @click="show = false">Close</v-btn>
    </template>
  </v-snackbar>
</template>

<script>
import { mapGetters } from 'vuex';

export default {
  computed: {
    ...mapGetters({
      message: 'snackbar/message',
      color: 'snackbar/color'
    }),
    show: {
      get() {
        return this.$store.state.snackbar.show
      },
      set(v) {
        this.$store.commit('snackbar/SET_SHOW', v)
      }
    }
  }
}
</script>

使用合成 api 插件

<template>
  <v-snackbar v-model="show" :color="color">
    {{ message }}
    <template v-slot:action="{ attrs }">
      <v-btn text v-bind="attrs" @click="show = false">Close</v-btn>
    </template>
  </v-snackbar>
</template>

<script>
import { defineComponent, computed } from '@vue/composition-api';

export default defineComponent({
  setup(_props, { root }) {
    const show = computed({
      get: () => root.$store.state.snackbar.show,
      set: (v) => root.$store.commit('snackbar/SET_SHOW', v),
    });
    const message = computed(() => root.$store.state.snackbar.message);
    const color = computed(() => root.$store.state.snackbar.color);

    return {
      show,
      message,
      color,
    };
  },
});
</script>

在这里使用可组合的更好的实现https://gist.github.com/wobsoriano/2f3f0480f24298e150be0c13f93bac20

【讨论】:

    【解决方案4】:

    你有一个道具和数据相同。

    data() 中删除小吃吧,因为它可从prop 获得。

    <script>
    export default {
      props: {
        snackbar: {
          type: Boolean,
          required: true,
        },
        color: {
          type: String,
          required: false,
          default: "success",
        },
        timeout: {
          type: Number,
          required: false,
          default: 3000,
        },
        text: {
          type: String,
          required: true,
        },
      }
    };
    </script>
    

    【讨论】:

    • 抱歉,这是我的错。我已经删除它但发生同样的错误
    • @KalanaMihiranga 您能否在代码框中为您提供该问题的代码,因为我无法重现该问题?
    猜你喜欢
    • 2021-05-13
    • 2020-02-20
    • 2016-03-17
    • 2021-12-09
    • 2021-12-08
    • 2017-12-14
    • 2021-01-20
    • 1970-01-01
    • 2019-09-01
    相关资源
    最近更新 更多