下面將會實現這樣的效果:
元件動態建立指令碼:
import Vue from "vue";
import Notice from "@/components/Noticer/Notice.vue";
function create(Component, props) {
// 先建立範例
const vm = new Vue({
render(h) {
//h就是createElement,它返回VNode
return h(Component, { props });
},
}).$mount();
// 手動掛載
// 判斷是否存在container,如果不存在則先建立
let container;
container = document.querySelector(".noticer-container");
if (container == null) {
container = document.createElement("div");
container.classList.add("noticer-container");
container.style.position = "fixed";
container.style.top = "50px";
container.style.right = "0px";
container.style.overflow = "hidden";
container.style.zIndex = 9999;
document.body.appendChild(container);
}
container.appendChild(vm.$el);
//銷燬方法
const comp = vm.$children[0];
comp.remove = function () {
container.removeChild(comp["$el"]);
vm.$destroy();
};
comp.show();
return comp;
}
Vue.prototype.$notice = {
error: function (props) {
create(Notice, Object.assign(props, { type: "error" }));
},
info: function (props) {
create(Notice, Object.assign(props, { type: "info" }));
},
success: function (props) {
create(Notice, Object.assign(props, { type: "success" }));
},
warn: function (props) {
create(Notice, Object.assign(props, { type: "warn" }));
},
};
這裡有一些值得注意的地方:
fixed
, 而之所以設定為 overflow:hidden
的原因則是,notice 在出現和移除的時候,發生的動畫偏移,會讓頁面出現橫向卷軸。為了避免重複建立container, 這裡做了一個判斷邏輯。然後所有動態生成的notice範例dom都會通過 appendChild
新增到這個容器。vm.$children[0]["$el"]
, 原因是,Notice 模板的實現中,外層套了一個 transition , 而這個transition是並不會渲染dom的。建立Notice元件模板:
<template>
<transition
enter-active-class="animate__animated animate__slideInRight"
leave-active-class="animate__animated animate__slideOutRight"
@after-leave="afterLeave"
>
<div v-if="isShow" class="notice__root">
<div :class="`notice-type-${type}`" class="noticer">
{{
type === "error"
? "🍓"
: type === "success"
? "🍀"
: type === "warn"
? "🍋"
: "🐳"
}}
: {{ message }}
</div>
</div>
</transition>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
message: {
type: String,
default: "",
},
time: {
type: Number,
default: 1000,
},
type: {
type: String,
},
},
data() {
return {
isShow: false,
};
},
methods: {
show() {
this.isShow = true;
setTimeout(this.hide, this.time);
},
hide() {
this.isShow = false;
},
afterLeave() {
this.remove();
},
},
};
</script>
<style lang="less" scoped>
@error: rgb(255, 30, 30);
@warn: rgb(240, 192, 0);
@success: rgb(0, 144, 74);
@info: rgb(0, 80, 218);
@errorBg: rgb(255, 208, 208);
@warnBg: rgb(255, 245, 207);
@successBg: rgb(210, 255, 233);
@infoBg: rgb(203, 222, 255);
.notice__root {
user-select: none;
padding: 5px 50px 5px 5px;
}
.noticer {
padding: 5px 20px;
margin: 10px 0px;
// margin-right: 50px;
border-radius: 8px;
font-size: 16px;
width: auto;
min-width: 280px;
max-width: 300px;
word-break: break-all;
text-align: center;
box-sizing: border-box;
}
.notice-type-error {
color: @error !important;
border: 2px solid @error;
box-shadow: 1px 1px 5px 2px @errorBg;
background-color: @errorBg;
// border: 1px solid red;
}
.notice-type-warn {
color: @warn !important;
border: 2px solid @warn;
background-color: @warnBg;
box-shadow: 1px 1px 5px 2px @warnBg;
}
.notice-type-success {
color: @success !important;
border: 2px solid @success;
background-color: @successBg;
box-shadow: 1px 1px 5px 2px @successBg;
}
.notice-type-info {
color: @info !important;
border: 2px solid @info;
background-color: @infoBg;
box-shadow: 1px 1px 5px 2px @infoBg;
}
</style>
在 main.js 中引入執行該指令碼即可
import Vue from "vue";
import App from "./App.vue";
import "animate.css";
import "@/components/Noticer/NotificationBanner.js";
new Vue({
render: (h) => h(App),
}).$mount("#app");
程式碼中使用範例:
if (!this.nickname) {
this.$notice.error({
message: "好漢!姓甚名誰?",
time: 3000,
});
} else {
this.showModal = false;
this.$notice.info({
message: this.nickname + "來了!!!",
time: 3000,
});
}
動態建立元件的執行邏輯:
當在使用的時候:
this.$notice.error({
message: "好漢!姓甚名誰?",
time: 3000,
});
上方程式碼觸發,實際上會觸發 NotificationBanner.js 中的 create
函數,該函數建立了一個notice 的元件範例,並在實力上新增了一個remove
方法,然後直接觸發元件中的 show
方法。
notice 模板範例中:
methods: {
show() {
this.isShow = true;
setTimeout(this.hide, this.time);
},
hide() {
this.isShow = false;
},
afterLeave() {
this.remove();
},
},
show
方法執行,除了展示 notice,立即設定一個延時函數執行 hide
方法。
hide
方法執行, vue 提供的 transition 勾點 afterleave()
會在移除動畫執行完畢後觸發。 這時候,去觸發 remove
方法,將該notice 元件範例移除。