<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
一個類似Element UI
、Ant-Design UI
等 UI 框架的訊息提示功能,方便在任何網頁環境中直接呼叫函數使用;區別在不依賴 js 及 css 參照,而是使用純 js 進行封裝實現,程式碼更精簡,同時保持和 UI 框架一樣的視覺效果(可自行修改成自己喜歡的樣式)
線上預覽效果(點選【登入】、【點選複製】按鈕時觸發提示效果)
<body>
中,保證提示條的程式碼結構位置永遠在最上層。<style> .msg-box { position: fixed; top: 0; left: 50%; display: flex; padding: 12px 16px; border-radius: 2px; background-color: #fff; box-shadow: 0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12); transform: translate3d(-50%, 0%, 0); } </style> <body> <div class="msg-box"></div> </body>
animation
作為進入動畫,因為節點一輸出就會執行了.msg-box { ...省略以上程式碼 animation: msg-move .4s; } @keyframes msg-move { 0% { opacity: 0; transform: translate3d(-50%, -100%, 0); } 100% { opacity: 1; transform: translate3d(-50%, 0%, 0); } }
transition
的過渡方式,即定義一個.hide
,之後通過 js 去控制切換 class 去實現過渡切換.msg-box { ...省略以上程式碼 opacity: 1; transition: .4s all; // 保持和 animation 的過渡時間一致 } .msg-box.hide { opacity: 0; transform: translate3d(-50%, -100%, 0); }
這裡樣式佈局就全部完成了,剩下的交給 js 去處理對應的操作邏輯。
<body>
下,有可能給其他dom
操作插入節點。所以在輸出節點的時候要將其存放起來,然後通過迴圈的方式去設定每一個節點的padding-top
,這樣就能保證視覺排列效果和程式碼操作的順序保持一致了,之後所做的刪除操作也是通過迴圈去設定每一個節點的padding-top
。/** * 訊息佇列 * @type {Array<HTMLElement>} */ const messageList = []; /** * 獲取指定`item`的定位`top` * @param {HTMLElement=} el */ function getItemTop(el) { let top = 10; // 起始的邊距 for (let i = 0; i < messageList.length; i++) { const item = messageList[i]; if (el && el === item) { break; } top += item.clientHeight + 20; // 兩個訊息條的間距為20 } return top; } /** * 刪除指定列表項 * @param {HTMLElement} el */ function removeItem(el) { for (let i = 0; i < messageList.length; i++) { const item = messageList[i]; if (item === el) { messageList.splice(i, 1); break; } } el.classList.add(".hide"); messageList.forEach(function (item) { item.style.top = `${getItemTop(item)}px`; }); }
addEventListener("animationend", fn)
setTimeout
(延遲 N 秒之後為節點新增.hide
)addEventListener("transitionend", fn)
/** 一直累加的定位層級 */ let zIndex = 1000; /** * 顯示一條訊息 * @param {string} content 內容 * @param {number} duration 持續時間,優先順序比預設值高 */ function show(content, duration) { const el = document.createElement("div"); el.style.top = `${getItemTop()}px`; el.style.zIndex = zIndex; el.innerHTML = content; zIndex++; messageList.push(el); document.body.appendChild(el); // 新增動畫監聽事件 function animationEnd() { el.removeEventListener("animationend", animationEnd); setTimeout(removeItem, duration || 3000, el); } el.addEventListener("animationend", animationEnd); function transitionEnd() { if (getComputedStyle(el).opacity !== "0") return; el.removeEventListener("transitionend", transitionEnd); el.remove(); } el.addEventListener("transitionend", transitionEnd); }
整個訊息輸出功能就完成了,最後只需要把對應的方法封裝起來並暴露需要呼叫的函數,並把css
樣式寫進方法裡就可以在任意地方使用了;css
寫進js
裡其實就是把上面寫好的樣式,通過字串模板的方式用變數接收並賦值給動態輸入的<style>
標籤就完事,另外樣式隔離可以通過模擬css.modeule
的方案去實現,具體看下面完整程式碼。
/** * 訊息提示條 * @param {object} params * @param {number} params.duration 持續時間(毫秒),預設`3000` * @param {number} params.zIndex 起始定位層級,預設`1000` */ function useMessage(params = {}) { const doc = document; const cssModule = `__${Math.random().toString(36).slice(2, 7)}`; const className = { box: `msg-box${cssModule}`, hide: `hide${cssModule}`, text: `msg-text${cssModule}`, icon: `msg-icon${cssModule}` } const style = doc.createElement("style"); style.textContent = ` .${className.box}, .${className.icon}, .${className.text} { padding: 0; margin: 0; box-sizing: border-box; } .${className.box} { position: fixed; top: 0; left: 50%; display: flex; padding: 12px 16px; border-radius: 2px; background-color: #fff; box-shadow: 0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12); white-space: nowrap; animation: ${className.box}-move .4s; transition: .4s all; transform: translate3d(-50%, 0%, 0); opacity: 1; overflow: hidden; } .${className.box}::after { content: ""; position: absolute; left: 0; top: 0; height: 100%; width: 4px; } @keyframes ${className.box}-move { 0% { opacity: 0; transform: translate3d(-50%, -100%, 0); } 100% { opacity: 1; transform: translate3d(-50%, 0%, 0); } } .${className.box}.${className.hide} { opacity: 0; /* transform: translate3d(-50%, -100%, 0); */ transform: translate3d(-50%, -100%, 0) scale(0); } .${className.icon} { display: inline-block; width: 18px; height: 18px; border-radius: 50%; overflow: hidden; margin-right: 6px; position: relative; } .${className.text} { font-size: 14px; line-height: 18px; color: #555; } .${className.icon}::after, .${className.icon}::before { position: absolute; content: ""; background-color: #fff; } .${className.box}.info .${className.icon}, .${className.box}.info::after { background-color: #1890ff; } .${className.box}.success .${className.icon}, .${className.box}.success::after { background-color: #52c41a; } .${className.box}.warning .${className.icon}, .${className.box}.warning::after { background-color: #faad14; } .${className.box}.error .${className.icon}, .${className.box}.error::after { background-color: #ff4d4f; } .${className.box}.info .${className.icon}::after, .${className.box}.warning .${className.icon}::after { top: 15%; left: 50%; margin-left: -1px; width: 2px; height: 2px; border-radius: 50%; } .${className.box}.info .${className.icon}::before, .${className.box}.warning .${className.icon}::before { top: calc(15% + 4px); left: 50%; margin-left: -1px; width: 2px; height: 40%; } .${className.box}.error .${className.icon}::after, .${className.box}.error .${className.icon}::before { top: 20%; left: 50%; width: 2px; height: 60%; margin-left: -1px; border-radius: 1px; } .${className.box}.error .${className.icon}::after { transform: rotate(-45deg); } .${className.box}.error .${className.icon}::before { transform: rotate(45deg); } .${className.box}.success .${className.icon}::after { box-sizing: content-box; background-color: transparent; border: 2px solid #fff; border-left: 0; border-top: 0; height: 50%; left: 35%; top: 13%; transform: rotate(45deg); width: 20%; transform-origin: center; } `.replace(/(n|t|s)*/ig, "$1").replace(/n|t|s({|}|,|:|;)/ig, "$1").replace(/({|}|,|:|;)s/ig, "$1"); doc.head.appendChild(style); /** 一直累加的定位層級 */ let zIndex = params.zIndex || 1000; /** * 訊息佇列 * @type {Array<HTMLElement>} */ const messageList = []; /** * 獲取指定`item`的定位`top` * @param {HTMLElement=} el */ function getItemTop(el) { let top = 10; for (let i = 0; i < messageList.length; i++) { const item = messageList[i]; if (el && el === item) { break; } top += item.clientHeight + 20; } return top; } /** * 刪除指定列表項 * @param {HTMLElement} el */ function removeItem(el) { for (let i = 0; i < messageList.length; i++) { const item = messageList[i]; if (item === el) { messageList.splice(i, 1); break; } } el.classList.add(className.hide); messageList.forEach(function(item) { item.style.top = `${getItemTop(item)}px`; }); } /** * 顯示一條訊息 * @param {string} content 內容 * @param {"info"|"success"|"warning"|"error"} type 訊息型別 * @param {number} duration 持續時間,優先順序比預設值高 */ function show(content, type = "info", duration) { const el = doc.createElement("div"); el.className = `${className.box} ${type}`; el.style.top = `${getItemTop()}px`; el.style.zIndex = zIndex; el.innerHTML = ` <span class="${className.icon}"></span> <span class="${className.text}">${content}</span> `; zIndex++; messageList.push(el); doc.body.appendChild(el); // 新增動畫監聽事件 function animationEnd() { el.removeEventListener("animationend", animationEnd); setTimeout(removeItem, duration || params.duration || 3000, el); } el.addEventListener("animationend", animationEnd); function transitionEnd() { if (getComputedStyle(el).opacity !== "0") return; el.removeEventListener("transitionend", transitionEnd); el.remove(); } el.addEventListener("transitionend", transitionEnd); } return { show, /** * 普通描述提示 * @param {string} msg */ info(msg) { show(msg, "info"); }, /** * 成功提示 * @param {string} msg */ success(msg) { show(msg, "success"); }, /** * 警告提示 * @param {string} msg */ warning(msg) { show(msg, "warning"); }, /** * 錯誤提示 * @param {string} msg */ error(msg) { show(msg, "error"); } } }
以上就是使用純JavaScript封裝一個訊息提示條功能範例詳解的詳細內容,更多關於JavaScript封裝訊息提示條的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45