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