下面將會實現這樣的效果:
-
元件動態建立指令碼:
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" })); }, };
這裡有一些值得注意的地方:
- container: 的作用是notice的容器,它可以用於定位notice在頁面的哪裡展示,注意notice不應該隨頁面捲動,因此其定位是
fixed
, 而之所以設定為overflow:hidden
的原因則是,notice 在出現和移除的時候,發生的動畫偏移,會讓頁面出現橫向滾動條。為了避免重複建立container, 這裡做了一個判斷邏輯。然後所有動態生成的notice例項dom都會通過appendChild
新增到這個容器。 - 在移除的時候, 移除的是
vm.$children[0]["$el"]
, 原因是,Notice 模板的實現中,外層套了一個 transition , 而這個transition是並不會渲染dom的。
- container: 的作用是notice的容器,它可以用於定位notice在頁面的哪裡展示,注意notice不應該隨頁面捲動,因此其定位是
-
建立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 元件例項移除。