【问题标题】:Create a global snackbar using Vue, Vuetify and Vuex使用 Vue、Vuetify 和 Vuex 创建一个全局小吃吧
【发布时间】:2021-05-13 03:58:15
【问题描述】:

我尝试创建一个全局的snackbar以在每次发生axios http错误时触发,我遵循了这个教程:https://dev.to/stephannv/how-to-create-a-global-snackbar-using-nuxt-vuetify-and-vuex-1bda

但我不想使用 Nuxt,只使用 Vue、Vuex 和 Vuetify,所以我尝试创建一个随处可用的插件,但出现以下错误:[vuex] unknown mutation type: snackbar/showMessageTypeError: Cannot read property '$snackbar' of undefined

这是我的代码:

src/main.js

import Vue from 'vue'
import router from "@/router";
import "./filters/filters";

import App from './App.vue'

import vuetify from "@/plugins/vuetify";

import VueSignaturePad from 'vue-signature-pad';
import axios from "axios";

import store from "@/store/snackbar";
import snackbarPlugin from "@/plugins/snackbar";

Vue.prototype.$http = axios;

Vue.config.productionTip = false

Vue.use(snackbarPlugin, { store });
Vue.use(VueSignaturePad);

axios.interceptors.response.use(
    function (response) {
        return response;
    },
    function (error) {
        // handle error
        if (error.response) {
            this.$snackbar.showMessage({ content: error.response.data, color: 'error', timeout: 10000 })
        }
    });

new Vue({
    router,
    store,
    vuetify,
    render: h => h(App)
}).$mount('#app')

src/store/snackbar.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
    state: {
        content: '',
        color: '',
        timeout: ''
    },
    mutations: {
        showMessage (state, payload) {
            state.content = payload.content
            state.color = payload.color
            state.timeout = payload.timeout
        }
    }
});

export default store;

src/plugins/snackbar.js

const snackbarPlugin = {
    install: (Vue, {store}) => {
        if (!store) {
            throw new Error('Please provide vuex store.');
        }

        Vue.prototype.$snackbar = {
            showMessage: function ({
                                       content = '',
                                       color = '',
                                       timeout = ''
                                   }) {
                store.commit(
                    'snackbar/showMessage',
                    {content, color, timeout},
                    {root: true}
                );
            }
        };
    },
};

export default snackbarPlugin;

src/utils/Snackbar.vue

<template>
    <v-snackbar v-model="show" :color="color" elevation="20">
        {{ message }}
        <v-btn color="accent" @click.native="show = false">
            <v-icon>close</v-icon>
        </v-btn>
    </v-snackbar>
</template>

<script>
export default {
    data() {
        return {
            show: false,
            message: "",
            color: "",
            timeout: 5000
        };
    },
    created () {
        this.$store.subscribe((mutation, state) => {
            if (mutation.type === 'snackbar/showMessage') {
                this.message = state.snackbar.content
                this.color = state.snackbar.color
                this.timeout = state.snackbar.timeout
                this.show = true
            }
        })
    }
};
</script>

src/App.vue

<template>
    <v-app>
        <Snackbar></Snackbar>
        <side-bar/>
        <Header/>
        <Main/>
    </v-app>
</template>

<script>
    import Snackbar from "@/utils/Snackbar";
    import SideBar from "@/components/layouts/SideBar";
    import Header from "@/components/layouts/Header";
    import Main from "@/components/layouts/Main";

    export default {
        name: 'App',
        components: {
            Snackbar,
            SideBar,
            Header,
            Main
        },
        beforeMount() {
            console.log('app')
            this.getRole()
            this.getEtats()
        },
        methods: {
            getRole() {
                this.$http.get('/rol')
                    .then(response => {
                        let agent = {}
                        agent.role = response.data.data.role
                        agent.username = response.data.data.username
                        localStorage.setItem('badge.agent', JSON.stringify(agent))
                    })
                    .catch(function (error) {
                        console.log(error)
                    })
            },
            getEtats() {
                this.$http.get('/nyx/badge/demande/accesnro/etats')
                    .then(response => {
                        localStorage.setItem('badge.etats', JSON.stringify(response.data.data))
                    })
                    .catch(function (error) {
                        console.log(error)
                    })
            }
        }
    }
</script>

我故意在 /role 路由上抛出 404 错误以调出小吃栏,但错误发生了。

当我打电话给this.$snackbar.showMessage ({content: error.response.data, color: 'error', timeout: 10000 }) in main.js 时,你知道有什么问题吗?

【问题讨论】:

    标签: plugins axios vuetify.js interceptor snackbar


    【解决方案1】:

    因为你不使用 Vuex 模块 (https://vuex.vuejs.org/guide/modules.html),所以你应该调用 commit 时不带snackbar 前缀:

    store.commit('showMessage',{
        content, color, timeout}
    );
    

    查看此帖子 (Using vuejs plugin on the main.js file)。有一个解释,如何在main.js和App中同时使用插件。

    main.js

    import Vue from "vue";
    import router from "@/router";
    import "./filters/filters";
    
    import App from "./App.vue";
    
    import vuetify from "@/plugins/vuetify";
    
    import VueSignaturePad from "vue-signature-pad";
    import axios from "axios";
    
    import store from "@/store/snackbar";
    import snackbarPlugin from "@/plugins/snackbar";
    
    Vue.prototype.$http = axios;
    
    Vue.config.productionTip = false;
    
    Vue.use(snackbarPlugin, { store });
    Vue.use(VueSignaturePad);
    
    axios.interceptors.response.use(
      function(response) {
        return response;
      },
      function(error) {
        // handle error
        if (error.response) {
          snackbarPlugin.showMessage({
            content: error.response.data,
            color: "error",
            timeout: 10000
          });
        }
      }
    );
    
    new Vue({
      router,
      store,
      vuetify,
      render: h => h(App)
    }).$mount("#app");
    

    snackbar.js

    import store from "../store/snackbar";
    
    const snackbarPlugin = {
      showMessage: ({ content = "", color = "", timeout = "" }) => {
        store.commit("snackbar/showMessage", { content, color, timeout }, { root: true });
      },
      install: (Vue, { store }) => {
        if (!store) {
          throw new Error("Please provide vuex store.");
        }
        Vue.prototype.$snackbar = snackbarPlugin;
      }
    };
    
    export default snackbarPlugin;
    

    main.js

    【讨论】:

    • 感谢您的回答。在main.js 中,我调用插件this.$snackbar.showMessage({ content: error.response.data, color: 'error', timeout: 10000 }),应该调用store.commit ('snackbar / showMessage',{content, color, timeout},{root: true}); 的插件不应该工作吗?
    • 此调用this.$snackbar.showMessage({ content: error.response.data, color: 'error', timeout: 10000 }) 成功。问题出在snackbar/showMessage 部分。 snackbar 代表命名空间的 vuex 模块和 showMessage 你的突变名称。但是您在商店中全局设置了showMessage。所以vuex返回错误:[vuex] unknown mutation type: snackbar/showMessage你可以很容易地调用showMessage或者创建snackbar模块。
    • 我在我的商店添加了这个:snackbar: { namespaced: true, 但是我仍然有这个错误:TypeError: Cannot read property '$snackbar' of undefined at eval (main.js:45) in main.js。也许我不能在这个位置使用关键字this 来调用我的插件?你能告诉我你的想法吗?
    • 我在上面更新了我的答案。希望,它会有所帮助。
    猜你喜欢
    • 2020-02-20
    • 2020-10-29
    • 2021-12-09
    • 2019-09-01
    • 2016-03-17
    • 1970-01-01
    • 2021-01-14
    • 2020-09-07
    • 2018-07-03
    相关资源
    最近更新 更多