给博客添加自定义的通知悬浮窗
|字数总计:2.1k|阅读时长:9分钟|阅读量:|
点击查看更新记录
- 修改悬浮窗ID的存储方式
- 移动端按钮描述文本改为常显
预览
点击下方按钮就可以查看带按钮的悬浮窗的样式了
点击触发特性
- 打开后超时自动关闭
- 附加关闭按钮,可手动关闭
- 鼠标悬浮在悬浮窗上会重置自动关闭计时器
- 附带全套动画
- 可以在悬浮窗上添加一个附带文字描述的按钮并自定义点击功能
- 可以同时显示多个悬浮窗(有上限,超过上限会直接关闭额外的悬浮窗)
- 适配黑白两色主题
- 好玩还好看
教程
首先我们新建一个JS文件,并写入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
btf.snackbarShow = (text, time = 3500) => kms.pushInfo(text, null, time)
const kms = {
isMobile: 'ontouchstart' in document.documentElement, _cache: { win: new Map(), winCode: 0 },
pushInfo: (text, button = null, time = 3500) => { const idMap = kms._cache.win
const moveWin = (id, direct) => { const list = document.getElementsByClassName('float-win') const moveHeight = document.getElementById(id).offsetHeight + 10 for (let i = list.length - 1; i !== -1; --i) { const div = list[i] if (div.id === id) break const value = parseInt(div.getAttribute('move')) + (direct ? -moveHeight : moveHeight) div.setAttribute('move', value) div.style.transform = `translateY(${value}px)` } }
const closeWin = (id, move = true) => new Promise(() => { const div = document.getElementById(id) if (!div || div.classList.contains('delete')) return div.onanimationend = () => { idMap.delete(div.id) document.body.removeChild(div) } div.classList.add('delete') div.style.transform = '' if (move) moveWin(id, true) }) const closeRedundantWin = maxCount => new Promise(() => { const list = document.getElementsByClassName('float-win') if (list && list.length > maxCount) { const count = list.length - maxCount for (let i = 0; i !== count; ++i) { closeWin(list[list.length - i - 1].id, false) } } }) const buildHTML = id => { const cardID = `float-win-${id}` const actionID = `float-action-${id}` const exitID = `float-exit-${id}` const buttonDesc = (button && button.desc) ? `<div class="descr"><p ${kms.isMobile ? 'class="open"' : ''}>${button.desc}</p></div>` : '' return `<div class="float-win ${button ? 'click' : '' }" id="${cardID}" move="0"><i class="fa fa-info-circle"></i><button class="exit" id="${exitID}"><i class="fa fa-times"></i></button><p class="text">${text}</p>${button ? '<div class="select"><button class="action" id="' + actionID + '">' + (button.icon ? '<i class="' + button.icon + '">' : '') + '</i><p class="text">' + button.text + `</p></button>${buttonDesc}` : ''}</div></div>` } const id = kms._cache.winCode++ document.body.insertAdjacentHTML('afterbegin', buildHTML(id)) const actionButton = document.getElementById(`float-action-${id}`) const exitButton = document.getElementById(`float-exit-${id}`) const cardID = `float-win-${id}` actionButton && actionButton.addEventListener('click', () => { closeWin(cardID) if (button.onclick) button.onclick() }) exitButton.addEventListener('click', () => closeWin(cardID)) const div = document.getElementById(cardID) div.onmouseover = () => div.setAttribute('over', true) div.onmouseleave = () => div.removeAttribute('over') moveWin(cardID, false) closeRedundantWin(3) const task = setInterval(() => { const win = document.getElementById(cardID) if (win) { if (win.hasAttribute('over')) return idMap.set(cardID, 0) const age = (idMap.get(cardID) || 0) + 100 idMap.set(cardID, age) if (age < time) return } clearInterval(task) closeWin(cardID) }, 100) return () => (closeWin(cardID), undefined) } }
|
接着我们新建一个styl
文件,并写入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
| .float-win
position fixed top 70px width 310px z-index 9997 background-color var(--km-float-win-bg) color var(--km-globle-font) border-radius 15px box-shadow 2px 2px 5px 3px var(--km-button-shadow) transition all 1s animation win-entrance 1.3s forwards
&.delete animation win-exit 1.2s forwards
@media screen and (max-width: 550px) and (min-width: 250px) width calc(65%)
@media screen and (max-width: 250px) width calc(80%)
& > .select > .descr color transparent
& > i margin-left 10px
& > .text position relative max-width 84% margin-left 8% text-align center margin-top 0 margin-bottom 20px word-break break-word word-wrap break-word
&.click & > .text margin-bottom 0
& > .exit position absolute color var(--km-globle-font) right 0 top 0 width 30px height 30px transition all 0.5s
&:hover color deepskyblue transform rotate(90deg)
& > .select position relative text-align right margin-bottom 10px height 30px
& > .descr position relative margin-top 0 margin-right 6px display inline-block height 30px overflow hidden
& > p position relative margin 0 height 30px z-index 9998 transition all 1s
&:not(.open) left 100px opacity 0
& > .action display inline-block position relative float right z-index 9999 height 30px margin-right 10px background-color var(--km-button-dark-bg) color var(--km-button-font) box-shadow 1px 1px 2px var(--km-button-shadow) padding 10px border-radius 7px transition all 0.5s
& > .text display inline position relative bottom 4px font-weight bold
& > i position relative bottom 4px margin-right 5px
&:hover background-color var(--km-button-dark-hover)
& + .descr > p left 0 opacity 1
[data-theme='light'] .float-win box-shadow 3px 4px 6px 5px var(--km-button-shadow)
@keyframes win-entrance from right -310px opacity 0.5 to right 20px opacity 1
@keyframes win-exit from right 20px to right -500px opacity 0.3
|
styl
中用到了一些变量,变量表如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| :root --km-float-win-bg whitesmoke --km-globle-font black --km-button-dark-hover #0084ff --km-button-dark-bg #66ccff --km-button-font white --km-button-shadow hsla(0, 0%, 22%, 0.2)
[data-theme="dark"] --km-float-win-bg #141414 --km-globle-font white --km-button-dark-hover #49505d --km-button-dark-bg #1f1f1f --km-button-font #66ccff --km-button-shadow #212121
|
最后在合适的地方引入刚刚编写的文件即可,具体用法我就说一点,注释里已经写的很详细了。
在这里写的几个函数中,所有以下划线(_
)开头的函数和变量均为内部调用,外部不应当调用。至于为什么外露出来,一是JS没有像其它语言那样的可见域控制(也有可能是有但是我不知道),二是方便调试。
笔记
虽然这个悬浮窗实现并不复杂,不过对于这种基本不懂前端开发,只会照葫芦画瓢的人来说还是比较有难度的,用了一下午才把悬浮窗弄好。 开发中也遇到了不少问题(不然也不会花这么长时间),难为我最长时间的就是悬浮窗内部元素的排版了,光想办法把按钮放在右边,提示文本放在左边就花费了至少一个小时。
不过通过这次实践,我也学到了不少东西,比如了解了更多的CSS 选择器
、了解了setInterval
的用法……
这的确是应了那句老话:“实践出真知。”多实践就能不断巩固已有的知识,同时学习新的知识。
下面的话主要实给同学看的
现在有不少人都称呼我为“大佬”,实际上我也就是在代码编写方面有稍微多一点的经验,看了我上面的话应该也不难发现,前端开发我就是个渣渣。实际上不仅是我,任何“大佬”都不会擅长所有领域。同时大佬也一定不是一天养成的,现在的我前端是渣渣,说不定以后我就是前端的大牛了呢?
所以也不要因为身边有那么几个水平超出自己非常多的人就自暴自弃,只要自己不放弃就有赶上甚至超越那些人的希望,一旦放弃就毫无希望了。
参考资料
创作不易,扫描下方打赏二维码支持一下吧ヾ(≧▽≦*)o