消息提示框在實際應用場景當中比較常見,最經常使用的就是element ui的消息提示框,咱們一般都是直接使用它們,可是咱們有沒有嘗試過去探究其實現原理,並本身動手實現呢?爲了提高咱們的我的能力和競爭力,咱們能夠嘗試來實現這樣一個消息提示框。css
咱們來查看一下最終實現效果,以下圖所示:html
咱們建立一個message文件夾,而後建立一個index.html文件,以及message.js和message.css文件,以下所示:es6
在html文件中,咱們能夠先來實現一個靜態的消息提示框,代碼以下:編程
<div class="message"> <p>這是一個提示框</p> <i class="message-close-btn">×</i> </div>
而後再message.css咱們寫上基本的css代碼:app
* { margin: 0; padding: 0; box-sizing: border-box; } /* 消息提示框容器樣式 */ .message { position: fixed; left: 50%; transform: translateX(-50%); display: flex; align-items: center; min-width: 300px; background-color: #edf2fc; border: 1px solid #edf2fc; padding: 16px 17px; top: 25px; border-radius: 6px; overflow: hidden; z-index: 1000; } /* 關閉按鈕樣式 */ .message > .message-close-btn { position: absolute; right: 15px; top: 50%; transform: translateY(-50%); color: #c0c0c4; font-size: 17px; cursor: pointer; } .message > .message-close-btn:hover,.message > .message-close-btn:active { color: #909399; } /* 消息提示框內容樣式 */ .message p { line-height: 1; font-size:14px; color: #909399; }
有四種提示框,以及讓內容居中,咱們不外乎是多加一個類名來寫css樣式,好比內容居中,咱們只須要在html消息提示框容器元素加上一個類名,代碼以下:函數
<div class="message message-center"> <p>這是一個提示框</p> <i class="message-close-btn">×</i> </div>
而後再css文件中加一段以下的css代碼便可:佈局
/* 內容居中 */ .message.message-center { justify-content: center; }
四種類型的提示框不外乎也是一樣的原理,增長一個類名,而後改變的是背景色和字體色,因此html代碼以下:字體
<div class="message message-success"> <p>這是一個成功提示框</p> <i class="message-close-btn">×</i> </div> <div class="message message-warning"> <p>這是一個警告提示框</p> <i class="message-close-btn">×</i> </div> <div class="message message-error"> <p>這是一個錯誤提示框</p> <i class="message-close-btn">×</i> </div>
css代碼以下:flex
/* 成功提示框樣式 */ .message.message-success { background-color: #e1f3d8; border-color:#e1f3d8; } .message.message-success p { color: #67c23a; } /* 警告提示框樣式 */ .message.message-warning{ background-color: #fdfce6; border-color: #fdfce6; } .message.message-warning p{ color: #e6a23c; } /* 錯誤提示框樣式 */ .message.message-error { background-color: #fef0f0; border-color: #fef0f0; } .message.message-error p { color: #f56c6c; }
這樣一來,準備工做就完成了,接下來就是咱們的重頭戲,JavaScript代碼,嘗試將如上代碼註釋掉。ui
咱們經過定義一個對象來表示消息提示框的類型,以下所示:
// 消息提示框的四種類型 let typeMap = { info: "info", warning: "warning", success: "success", error: "error" }
咱們分析一下須要傳入的配置項有內容(content),關閉提示框時間(closeTime),是否顯示關閉提示框按鈕(showClose),內容居中(center)以及消息提示框類型(type)。因此定義配置項以下:
// 提示框的默認配置項 let messageOption = { type: "info", closeTime: 600, center: false, showClose: false, content: "默認內容" }
咱們經過面向對象的編程思惟將消息提示框當作是一個類對象,因此咱們只須要建立一個類。雖然可使用es6的class語法來建立,可是爲了方便,咱們使用構造函數來實現。建立一個構造函數Message,以下所示:
function Message(option) { //這裏作了一次初始化 this.init(option); }
建立了消息提示框構造函數以後,咱們須要傳入配置項,而且咱們在函數裏作了初始化操做,接下來咱們來實現初始化的操做。
Message.prototype.init = function (option) { //這裏建立了提示框元素,並將整個提示框容器元素添加到頁面中 document.body.appendChild(this.create(option)); //這裏設置提示框的top this.setTop(document.querySelectorAll('.message')); //判斷若是傳入的closeTime大於0,則默認關閉提示框 if (option.closeTime > 0) { this.close(option.container, option.closeTime); } //點擊關閉按鈕關閉提示框 if (option.close) { option.close.onclick = (e) => { this.close(e.currentTarget.parentElement, 0); } } }
在前面的初始化操做中,咱們作了幾個功能,首先建立提示框容器元素,並將提示框容器元素添加到頁面bod中。咱們還作了動態計算提示框的top以及判斷傳入的默認關閉時間來關閉提示框,點擊關閉按鈕關閉提示框。咱們來看建立提示框的方法,即create方法的編寫操做。以下:
Message.prototype.create = function (option) { //這裏作了一個判斷,表示若是設置showClose爲false即不顯示關閉按鈕而且closeTime也爲0,即無自動關閉提示框,咱們就顯示關閉按鈕 if(!option.showClose && option.closeTime <=0)option.showClose = true; //建立容器元素 let element = document.createElement('div'); //設置類名 element.className = `message message-${option.type}`; if (option.center) element.classList.add('message-center'); //建立關閉按鈕元素以及設置類名和內容 let closeBtn = document.createElement('i'); closeBtn.className = 'message-close-btn'; closeBtn.innerHTML = '×'; //建立內容元素 let contentElement = document.createElement('p'); contentElement.innerHTML = option.content; //判斷若是顯示關閉按鈕,則將關閉按鈕元素添加到提示框容器元素中 if (closeBtn && option.showClose) element.appendChild(closeBtn); //將內容元素添加到提示框容器中 element.appendChild(contentElement); //在配置項對象中存儲提示框容器元素以及關閉按鈕元素 option.container = element; option.close = closeBtn; //返回提示框容器元素 return element; }
咱們能夠看到,咱們建立了一個close方法,並傳入提示框容器元素,來實現關閉一個提示框,接下來咱們來實現這個關閉方法。以下所示:
Message.prototype.close = function (messageElement, time) { //根據傳入的時間來延遲關閉,實際上也就是移除元素 setTimeout(() => { //判斷若是傳入了提示框容器元素,而且分兩種狀況,若是是多個提示框容器元素則循環遍歷刪除,若是是單個提示框容器元素,則直接刪除 if (messageElement && messageElement.length) { for (let i = 0; i < messageElement.length; i++) { if (messageElement[i].parentElement) { messageElement[i].parentElement.removeChild(messageElement[i]); } } } else if (messageElement) { if (messageElement.parentElement) { messageElement.parentElement.removeChild(messageElement); } } //關閉了提示框容器元素以後,咱們從新設置提示框的top值 this.setTop(document.querySelectorAll('.message')); }, time * 10); }
最後咱們須要實現的是動態計算消息提示框的top,而後不讓消息提示框重疊在一塊兒。代碼以下:
Message.prototype.setTop = function (messageElement) { //這裏作一個判斷的緣由就是當點擊頁面中最後一個提示框的時候,會從新調用一次,這時獲取不到提示框容器元素,因此就不執行後續的設置top if (!messageElement || !messageElement.length) return; //因爲每一個提示框的高度同樣,因此咱們只需獲取第一個提示框元素的高度便可 const height = messageElement[0].offsetHeight; for (let i = 0; i < messageElement.length; i++) { //每一個提示框的top由一個固定值加上它的高度,而且咱們要乘以它的一個索引值 messageElement[i].style.top = (25 * (i + 1) + height * i) + 'px'; } }
咱們想要這樣調用$message()
或者$message.info()
,那麼咱們能夠實現以下:
let $message = {}; window['$message'] = $message = function (option) { let newMessageOption = null; if (typeof option === 'string') { newMessageOption = Object.assign(messageOption, { content: option }); } else if (typeof option === 'object' && !!option) { newMessageOption = Object.assign(messageOption, option); } return new Message(newMessageOption); } for (let key in typeMap) { window['$message'][key] = function (option) { let newMessageOption = null; if (typeof option === 'string') { newMessageOption = Object.assign(messageOption, { content: option,type:typeMap[key] }); } else if (typeof option === 'object' && !!option) { newMessageOption = Object.assign(JSON.parse(JSON.stringify(messageOption)),option,{ type:typeMap[key] }); } return new Message(newMessageOption); } }
整個邏輯也十分簡單,無非就是判斷傳入的配置項,而後進行合併,並傳入實例化的Message中。
如此一來,咱們就完成了一個消息提示框。
若是以上分析還不懂的話,能夠查看我錄製的一個視頻: