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':只在該元素當中,在該元素第一個子孩子前面。
'beforeend':只在該元素當中,在該元素最后一個子孩子后面。
'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é)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2021-01-01
Vue2.0父組件與子組件之間的事件發(fā)射與接收實例代碼
這篇文章主要介紹了Vue2.0父組件與子組件之間的事件發(fā)射與接收實例代碼,需要的朋友可以參考下2017-09-09
VUE中setTimeout和setInterval自動銷毀案例
這篇文章主要介紹了VUE中setTimeout和setInterval自動銷毀案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
關(guān)于配置babel-plugin-import報錯的坑及解決
這篇文章主要介紹了關(guān)于配置babel-plugin-import報錯的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12

