Message組件實現(xiàn)發(fā)財UI?示例詳解
引言
最近在實現(xiàn)Message組件,就是會從屏幕頂端彈出的一個小提醒,過一會兒就消失了。我個人非常喜歡這個設(shè)計,感覺在后續(xù)的復(fù)用性也很高,于是就打算自己手寫一個作為發(fā)財UI的組件
支持的功能
目前的Message有四種類型:
普通提醒 normal
成功提醒 success
警告提醒 warning
錯誤提醒error
同時還支持設(shè)置持續(xù)的時間:
使用方法
是不是非常簡單??
<template> <div> <button @click="popNormalMsg">打開一個普通提醒</button> </div> </template> <script lang="ts"> import {popMessage} from "../../lib/popMessage"; export default { name: "Message1.demo", components: {Button}, setup() { const popNormalMsg = () => { popMessage({ message: '這是一個全局顯示的普通提醒', //提醒內(nèi)容 msgType: 'normal', //提醒類型normal success error warning closeDelay: '2000', //顯示的時長,以ms為單位 }) } return {popNormalMsg} } } </script>
實現(xiàn)過程
如何實現(xiàn)不同類型的切換?
其實切換類型只是切換圖標而已哈哈哈
這里使用了IconPark圖標庫,這里使用了一個投機取巧的辦法,把不同的圖標命名為相應(yīng)的type,可以節(jié)省一些處理的步驟
href=#normal | msgType='normal' |
href=#success | msgType='success' |
href=#warning | msgType='warning' |
href=#error | msgType='error' |
const typeIndicator = `<use href="#${props.msgType}" rel="external nofollow" rel="external nofollow" ></use>`
<template> <div ref="msgDiv" class="rich-message"> <svg class="iconpark-icon" v-html="typeIndicator"> //2??typeIndicator的內(nèi)容會原封不動的跑到這里 </svg> //3??最后和svg標簽一起變成type對應(yīng)的圖標 <div class="rich-message-msgText">{{ message }}</div> </div> </template> <script lang="ts"> export default { name: "Message", props: { message: { type: String, required: true, }, msgType: { type: String, default: 'normal', }, }, setup(props) { const typeIndicator = `<use href="#${props.msgType}" rel="external nofollow" rel="external nofollow" ></use>` return {typeIndicator} //1??接受到傳來的type,然后typeIndicator會自動變?yōu)橄鄳?yīng)的圖標use標簽 } } </script>
如何實現(xiàn)Message的彈出和消失?
使用了CSS的transform,實際上就是Message在初始狀態(tài)下是藏在畫面外的,通過添加一個.message-active的類來讓它顯示出來,在經(jīng)過closeDelay毫秒后移除.message-active類。
.rich-message { ... transform: translateY(-100px); transition: all 250ms; &.message-active { transform: translateY(0px); opacity: 1; } }
如何實現(xiàn)往下排列而非堆疊?
為了讓他們能夠一個一個的排列下來而不是堆疊在一起,我想到了insertAdjacentElement()方法
element.insertAdjacentElement(position, element);
position有下面四種取值
'beforebegin': 在該元素本身的前面。
'afterbegin':只在該元素當(dāng)中,在該元素第一個子孩子前面。
'beforeend':只在該元素當(dāng)中,在該元素最后一個子孩子后面。
'afterend': 在該元素本身的后面。
不難發(fā)現(xiàn)這里似乎可以使用beforeend和afterend。經(jīng)過我的思考,為了保持DOM樹的整潔,我采用了創(chuàng)建一個msgContainer的div來存放所有的Message的方法,因此我也相應(yīng)的使用了beforeend
let msgContainer = document.getElementById('msgDiv') if (msgContainer === null) { msgContainer = document.createElement('div') msgContainer.id = 'msgDiv' document.body.appendChild(msgContainer) } const div = document.createElement('div'); //這個div就是Message所在的div msgContainer.insertAdjacentElement('beforeend', div)
給msgContainer一個CSS樣式
#msgDiv { position: absolute; top: 0; left: 50%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; justify-content: center; }
如何實現(xiàn)添加和移除.message-active類?
如果msgDiv在創(chuàng)建時就帶有.message-active類,那么將會閃現(xiàn)在頁面中,所以msgDiv應(yīng)該是在渲染后被添加了.message-active類,為了實現(xiàn)這個效果,使用了一個setTimeout()。
同時在closeDelay之后將這個類移除。
但是這樣存在一個問題,這個msgDiv只是看不見了,依然存在于DOM樹中。
setTimeout(() => { msgDiv.classList.add('message-active') }, 0) setTimeout(() => { msgDiv.classList.remove('message-active') }, closeDelay * 1);
如何將隱藏的Message從DOM樹中移除
在Message的淡出動畫結(jié)束后移除就好了,這里使用了.ontransitionendAPI,但是還存在問題,即如果有多個Message,他們會同時消失,原因是雖然每個Message在創(chuàng)建時都會有一個計時器,但是在移除時卻是所有的msgDiv一起移除,因此需要有區(qū)分的方法。
setTimeout(() => { msgDiv.classList.remove('message-active') msgDiv.ontransitionend = () => { app.unmount(); div.remove(); } }, closeDelay * 1);
如何區(qū)分不同的Message?
在本項目中,我使用了隨機生成ID的方式,如此一番就能精準的控制每個msgDiv
function randomLetter(len) { let str = ''; for (let i = 0; i < len; i++) { str += String.fromCharCode(~~(Math.random() * 26 + 65)); } return str; } const msgId = randomLetter(~~(Math.random() * 10 + 30)) //生成了一個隨機字符串 const app = createApp({ render() { return h(Message, { message, msgType, id: msgId, }); } }); app.mount(div); const msgDiv = document.getElementById(String(msgId)) setTimeout(() => { msgDiv.classList.add('message-active') }, 0) setTimeout(() => { msgDiv.classList.remove('message-active') msgDiv.ontransitionend = () => { app.unmount(); div.remove(); } }, closeDelay * 1);
最后的一個小細節(jié)
我們使用了一個msgContainer將所有的Message包裹的起來,從而實現(xiàn)順序排列,但是在最后一個Message消失后,msgContainer會作為一個空的div仍然存在于DOM樹中,這很不環(huán)保,因此在最后一個Message消失后將msgContainer也一并移除
setTimeout(() => { msgDiv.classList.remove('message-active') msgDiv.ontransitionend = () => { app.unmount(); div.remove(); if (msgContainer.children.length === 0) { msgContainer.remove() } } }, closeDelay * 1);
以上就是Message組件實現(xiàn)發(fā)財UI 示例詳解的詳細內(nèi)容,更多關(guān)于Message組件發(fā)財UI 的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Element-ui 自帶的兩種遠程搜索(模糊查詢)用法講解
這篇文章主要介紹了Element-ui 自帶的兩種遠程搜索(模糊查詢)用法講解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Vue2.0父組件與子組件之間的事件發(fā)射與接收實例代碼
這篇文章主要介紹了Vue2.0父組件與子組件之間的事件發(fā)射與接收實例代碼,需要的朋友可以參考下2017-09-09VUE中setTimeout和setInterval自動銷毀案例
這篇文章主要介紹了VUE中setTimeout和setInterval自動銷毀案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09關(guān)于配置babel-plugin-import報錯的坑及解決
這篇文章主要介紹了關(guān)于配置babel-plugin-import報錯的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12