给掘金写了个有趣又好玩的一键三连插件 | 仿B站效果
theme: fancy
我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!
先来看看b站的一键三连是什么效果:
不难观察出以下几个特点:
- 长按点赞出现抖动动画
- 长按点赞时关联按钮会有圆环进度条效果
- 长按超过一段时间后放开则一次实现三个动作并且有个绽放特效
接下来我们要做的就是逐步实现这些步骤,如何开始呢?这就需要介绍今天的主角:谷歌扩展插件。
创建一个Chrome插件
Chrome插件是一个用Web技术开发、用来增强浏览器功能的软件,它其实就是一个由HTML、CSS、JS、图片等资源组成的一个.crx后缀的压缩包。可以通过 chrome-plugin-demo 这个项目了解更多,这里我们直接讲如何使用:
首先在谷歌浏览器直接打开地址 chrome://extensions/ 进入扩展程序,并打开右上角开发者模式,这时就可以加载我们的插件了:
展程序会以 manifest.json
这个文件来识别并加载插件:
```json { "manifest_version": 2, "name": "掘金一键三连小助手", "version": "1.0", "description": "通过Chrome插件实现的一键三连效果,长按点赞3秒即可点赞+收藏+关注", "author": "ShawnPhang", "icons": { "48": "icon.png", "128": "icon.png" }, "page_action": { "default_icon": "icon.png", "default_title": "我是pageAction", "default_popup": "popup.html" }, "content_scripts": [ { "matches": ["http://juejin.cn/*"], "js": ["mojs.js", "inject.js"], "css": ["like.css"] } ], "background": { "scripts": ["background.js"] }, "web_accessible_resources": [] }
```
| 加载后效果 | 状态栏效果 | | --- | --- | | | |
在这个json文件中最主要看 content_scripts
这段配置,它表示了插件会向网页注入的JS文件和CSS文件,前面说了谷歌插件既是由一系列网页文件构成的,那么接下来就可以正式开始我们的效果实现了~
长按抖动
这是最容易实现的一个效果了,这里我定义了一个 shaking
的类,重复执行一段css动画,主要就是利用 translate
属性重新定位元素,就可以做到抖动的效果,下面的css也是非常随意写的,效果还可以。虽然只是上下左右位移却使用了 translate3d
,是为了触发css的3d加速性能会更好。
``` .article-suspended-panel > .shaking { animation: shake 350ms linear; animation-iteration-count: infinite; animation-direction: reverse; }
@keyframes shake { 10%, 90% { transform: translate3d(-1px, 0, 0); } 15%, 85% { transform: translate3d(0, -1px, 0); } 20%, 80% { transform: translate3d(+2px, 0, 0); } 25%, 75% { transform: translate3d(0, +2px, 0); } 30%, 70% { transform: translate3d(-2.5px, 0, 0); } 35%, 65% { transform: translate3d(0, -2.5px, 0); } 2.50%, 60% { transform: translate3d(+2.5px, 0, 0); } 2.55%, 55% { transform: translate3d(0, +2.5px, 0); } 50% { transform: translate3d(-2.5px, -2.5px, 0); } } ```
接下来在 inject.js
中只需要捕获文章页面点赞按钮,为其添加 mousedown
的监听事件,在点下鼠标的时候动态添加上 shaking
这个class,动画就开始执行了:
```js const likeBtn = document.querySelector('.article-suspended-panel .panel-btn')
likeBtn?.addEventListener('mousedown', () => { if (likeBtn.className.includes('active')) { return } likeBtn.classList.add('shaking') }) ```
圆环进度条
这个效果开始有点难度了,需要分两个Div来画,我们都知道一个完整的圆是这样:
css
.circle {
width: 4rem;
height: 4rem;
border: 2px solid red;
border-radius: 50%;
box-sizing: border-box;
}
这时我们先把红色边改为透明,然后只显示其中两条,并旋转一个角度,这就得到了半圆效果:
css
.circle {
....
border: 2px solid transparent;
border-top: 2px solid #1e80ff;
border-right: 2px solid #1e80ff;
transform: rotate(-135deg);
}
现在以这个半圆我们先来绘制右半部分的圆环,在这个 circle
元素父级添加一个外层元素,使结构如下:
```html
```
外层的 wrapper
高度和圆环高度一致,宽度则为一半,绝对定位到右边,此时效果是这样的:
css
.wrapper {
width: 2rem;
height: 4rem;
position: absolute;
right: 0;
background: yellow;
}
这时我们先写个css动画让 circle
转起来:
css
.circle .rightcircle {
right: 0;
animation: circle 3s linear infinite;
}
@keyframes circle {
0% {
transform: rotate(-135deg);
}
50%,
100% {
transform: rotate(45deg);
}
}
此时黄色区域为圆环的父级元素,如果我们将该区域视为可视区,那么只需要设置溢出隐藏:
css
.wrapper {
.....
overflow: hidden;
}
效果就出来了:
同样的方法绘制左半圆,叠加在一块就形成了环形进度条动画,核心在于两个Div的动画执行时间是一致的,也就是完整跑完一个360°的旋转周期,只不过各自都有一半被遮住,从而形成了最终效果,下面有请码上掘金为我们演示完整代码:
回到我们刚刚插件中,在点赞按钮点下的事件中我们需要批量添加上面这段DOM
到相应的操作按钮中,然后绝对定位在左上角(0,0)处即可,查看网页源代码可知按钮宽高为 4rem
,颜色我们则取全局变量中的蓝色 var(--juejin-brand-1-normal)
,将相关CSS写到 like.css
文件中后,JS中定义一个创建DOM
的函数:
js
function createCircle() {
const fragment = document.createElement('div')
fragment.classList.add('circle_process')
fragment.innerHTML = `<div class="wrapper right">
<div class="circle rightcircle"></div>
</div>
<div class="wrapper left">
<div class="circle leftcircle"></div>
</div>`
return fragment
}
因为这段结构还是有点多的,就不一一使用Element片段去创建了,创建完最外层的Div之后直接使用innerHtml
写入两个半圆的结构,函数返回这个DOM
片段。
下面就是在点击事件中处理相关动作,用时间戳判断长按时间是否持续3秒,用一个数组存储好创建的片段,鼠标抬起时循环调用其.remove()
方法来移除DOM
,b站的效果当然更加复杂,在这里并不是直接终止动画而是逆向运行动画,由于我们是使用css实现的,就折腾不了这种细节了,直接上代码:
```js let doms = [] let timeStamp = 0
const likeBtn = document.querySelector('.article-suspended-panel .panel-btn') likeBtn?.addEventListener('mousedown', () => { if (likeBtn.className.includes('active')) { return } timeStamp = new Date().getTime() / 1000 likeBtn.classList.add('shaking') doms.push(createCircle(), createCircle()) document.getElementsByClassName('panel-btn')[0].appendChild(doms[0]) document.getElementsByClassName('panel-btn')[2].appendChild(doms[1]) }) likeBtn?.addEventListener('mouseup', () => { likeBtn.click() const now = new Date().getTime() / 1000 const pass = now - timeStamp > 2.9 likeBtn.classList.remove('shaking') // 移除震动 for (const iterator of doms) { // 移除圆环 iterator.remove() } if (likeBtn.className.includes('active')) { return } if (pass) { // TODO: follow and collect btn action } }) ```
粒子绽放效果
这个效果用css实现难度更高了,刚好我今天在掘金看了一篇文章,介绍了一个轻量级动画库 mojs,里面的爆裂(Burst)效果就很适合这个场景,于是把umd文件下载来引入页面中。
inject.js
中定义一个函数执行来动画:
js
function play(parent, cb) {
new window.mojs.Burst({
// 爆裂范围 {从多大 : 到多大}
radius: { 0: 50 },
// 动画挂载的父元素, 如果不填默认挂载到 <body>
parent,
// 动画延迟的贝塞尔曲线函数
easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
// 动画延迟时间
duration: 1500,
// 在动画动之前等待的时间 (这里一般设置150ms方便减少低端机型可能会存在的卡顿)
delay: 300,
// 扩散的粒子配置
children: {
duration: 750,
// 粒子大小变换 {从多大 : 到多大}
// rand(from, to) rand函数可以帮我们随机出一个区间的值
radius: { 0: 'rand(5, 25)' },
// 形状选择, 这里我们选择了 “圆形”
shape: 'circle',
// 粒子可选的填充色
fill: ['#1abc9c', '#2ecc71', '#00cec9', '#3498db', '#9b59b6', '#fdcb6e', '#f1c40f', '#e67e22', '#e74c3c', '#e84393'],
},
// 透明度
opacity: 0.6,
// 生成的粒子数量
count: 12,
onStart() {
// 动画触发前的钩子函数
},
onComplete() {
// 动画完成后的钩子函数
cb && cb()
},
}).play()
}
接着在 mouseup
事件中调用:
js
..........
likeBtn?.addEventListener('mouseup', () => {
.............
if (pass) {
play(likeBtn, () => { // 这里只有两个按钮所以直接用回调函数来排列动画了
play(document.getElementsByClassName('panel-btn')[2])
})
}
})
完整效果展示(后面长按时间调整到2s):
插件完整代码地址:chromePlugin-juejin-oneThree
- 5年前端,裁员失业,迷茫中坚定「2022年终总结」
- 给掘金写了个有趣又好玩的一键三连插件 | 仿B站效果
- 原生拖拽太拉跨了,纯JS自己手写一个拖拽效果,纵享丝滑
- 这道 JS 经典面试题不要背!今天帮你彻底搞懂它
- 【melonJS】几十行 JS 代码简单编写一个小游戏「寻找掘金酱」
- 时隔一年多 jQuery 再度发布 3.6.1 新版本,你还在用JQ吗?
- 当UI走查说页面色值错误时,先别急着检查代码
- 我用三个月时间仿造了一个稿定设计 | 2022年中总结
- Puppeteer Nodejs 通用全屏网页截图方案(六)项目优化
- Puppeteer Nodejs 通用全屏网页截图方案(四)页面处理
- Puppeteer Nodejs 通用全屏网页截图方案(二)常用参数实现
- Puppeteer Nodejs 通用全屏网页截图方案(一)基本功能
- 一文带你认识 NodeJs
- 前端工程化的发展及工具介绍(三)
- 2022年了,前端的变化是否和尤大说的一样?vite生产使用体验
- 微前端很好,为什么我却不使用?
- 快速部署Grafana日志监控 Nginx封禁IP