本文演示一下如何为Vue/Vuetify项目添加全局的消息条(也叫toasts, snackbar).

我们期待的用法大概长这样

1
2
3
this.$q.error("")
this.$q.warning("")
this.$q.info("")

Store

把数据存在store中

store/snackbar.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const state = () => ({
content: "",
color: ""
});
const mutations = {
showMessage(state, payload) {
state.content = payload.content;
state.color = payload.color;
}
};
export default {
namespaced: true,
state,
mutations
};

并在store/index.js中引入它

1
2
3
4
5
6
7
8
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {
snackbar
}
});

Plugin

为了在全局都可以使用,我们需要创建一个插件

plugins/snackbar.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const snackbarPlugin = {
install: (Vue, { store }) => {
if (!store) {
throw new Error("Please provide vuex store.");
}
Vue.prototype.$q = {
showMessage: function({ content = "", color = "" }) {
store.commit(
"snackbar/showMessage",
{ content, color },
{ root: true }
);
},
error: function(content) {
store.commit(
"snackbar/showMessage",
{ content, color: "error" },
{ root: true }
);
},
warning: function(content) {
store.commit(
"snackbar/showMessage",
{ content, color: "warning" },
{ root: true }
);
},
info: function(content) {
store.commit(
"snackbar/showMessage",
{ content, color: "info" },
{ root: true }
);
}
};
}
};
export default snackbarPlugin;

需要在注册到Vue的全局对象上

main.js

1
2
import snackbarPlugin from "./plugins/snackbar";
Vue.use(snackbarPlugin, { store });

Component

消息条的组件则直接用Vuetify的就好了。

components/Snackbar.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
<v-app>
<v-snackbar v-model="show" :color="color" top text timeout="2000">
{{ message }}
<template v-slot:action="{ attrs }">
<v-btn text v-bind="attrs" @click="show = false">
Close
</v-btn>
</template>
</v-snackbar>
</v-app>
</template>
export default {
data() {
return {
show: false,
message: "",
color: ""
};
},

created() {
this.$store.subscribe((mutation, state) => {
if (mutation.type === "snackbar/showMessage") {
this.message = state.snackbar.content;
this.color = state.snackbar.color;
this.show = true;
}
});
}
};
</script>

Layout

把组件添加到应用中

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>
<router-view />
<Snackbar></Snackbar>
</div>
</template>
<script>
export default {
name: "App",
components: {
Snackbar: () => import("@/components/Snackbar.vue")
}
};
</script>

Usage

可以在任意页面中使用啦。

1
2
3
this.$q.info("xxx")
this.$q.warning("xxx")
this.$q.error("xxx")

在axios的response钩子中提示错误:

utils/request.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import axios from "axios";
import context from "@/main";
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 6000
});
service.interceptors.response.use(
response => {
const res = response.data;
return res;
},
async error => {
context.$q.error(error.response.data.detail);
return Promise.reject(error);
}
);
export default service;

Reference