🐇年新春,快来领取你的春节全屏动效吧🌈
我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛”
这算是我的第一篇技术文吧,有什么不对的地方请及时指正,鸣谢。
效果
所有言语都过于苍白,效果直达车(github),进不去github的话点这个👉 码上掘金链接
代码已开源,github地址~。如果喜欢这个全屏效果请动动小手点个star⭐,谢谢!
构想
当然要先选一张春节图片啦
body {
position: relative;
width: 100%;
height: 100vh;
background: url("../img/bg.png") center no-repeat;
background-size: cover;
overflow: hidden;
}
复制代码
思来想去,决定用emoji,选用了几个有关兔年和春节的小表情。因为是兔年,我也属兔,多加几个小🐇不过分吧~
const emoteList = ['🐰', '🐇', '🧨', '🎉', '🐇', '🏮', '🐰', '💰', '⛄', '🐇', '❄', '🧧']
复制代码
使用了jquery,因为用到了动画队列。
动画步骤
动画分为三个阶段
- 从顶部移动到屏幕底部
- 表情缩放
- 表情消失
代码
获取视窗可视区域
const innerW = window.innerWidth
const innerH = window.innerHeight
复制代码
创建表情标签
随机表情大小、位置、透明度、文字阴影以及过渡效果我是吃“随机”长大的吗
在表情数组里随机表情,然后返回dom、随机初始信息。
/**
* @function 生成随机表情元素
* @returns {{emoteEl: HTMLDivElement, emoteParams: {left: number, top: number, opacity: number, fs: number, transitionDuration: number}}}
*/
const createEmoteElement = () => {
const fs = 20 + Math.round(Math.random() * 16)
const left = Math.round(Math.random() * ((innerW - (fs / 2)) - (fs / 2)))
const top = -fs - 10
const opacity = ((Math.random() * 16 + 84) / 100).toFixed(2) - 0
const transitionDuration = 2000 + Math.round(Math.random() * 2000);
const emoteEl = $('<div></div>').css({
position: 'absolute',
color: '#fff',
top: `${ top }px`,
left: `${ left }px`,
fontSize: `${fs }px`,
opacity: opacity,
zIndex: 9999,
textShadow: `0 0 ${ fs / 4 }px #ffffff80`,
transition: `transform ${ transitionDuration }ms linear`
}).html(emoteList[Math.round(Math.random() * (emoteList.length - 1))])
return { emoteEl, emoteParams: { fs, left, top, opacity, transitionDuration } }
}
复制代码
设置动画
- 设置第一阶段动画位移的距离、时间(随机)
- 设置第二阶段动画的缩放比例(随机)
- 设置第三阶段动画小时时间(随机)
- 动画结束后删除dom标签
const setEmoteAnimate = () => {
const { emoteEl, emoteParams } = createEmoteElement()
$('body').append(emoteEl)
const endLeft = emoteParams.left + [-80, 80][Math.round(Math.random())]
const endTop = innerH - emoteEl.height() + Math.round(Math.random() * 10)
const moveDuration = innerH * 10 + Math.round(Math.random() * 4000);
const endScale = 1.2 + ((Math.round(Math.random() * 4) / 10).toFixed(2) - 0);
const hideDuration = 1200 + Math.round(Math.random() * 2000);
emoteEl.animate({ left: `${ endLeft }px`, top: `${ endTop }px`, }, moveDuration, 'linear', () => {
emoteEl.css({ transform: `scale(${ endScale })` })
.animate({ opacity: 0 }, hideDuration, 'linear', () => (emoteEl.remove()))
})
}
复制代码
开始动画
const start = () => setInterval(() => setEmoteAnimate(), 320)
$(document).ready(() => start())
复制代码
至此,全屏动画已经完成,看看效果。
优化
动画虽然完成,但是还有一些问题需要优化
问题
- 拖动改变浏览器大小时,innerW、innerH未及时校正,动画落点会有bug。
- pc端表情应较大、数量应较多;移动端表情应较小,数量也应有所减少。
- pc端背景图不适合移动端
解决问题
实时更新innerW、innerH
对更新频率做了节流。
let innerW, innerH
const setInnerSize = () => {
innerW = window.innerWidth
innerH = window.innerHeight
}
let num = 0
const start = () => setInterval(() => {
if (num % 10 === 0) setInnerSize()
num += 1
setEmoteAnimate()
}, 320)
复制代码
针对pc端、移动端适配
判断是pc端还是移动端
/**
* @function JudgePC 判断是当前浏览器信息是否为pc
* @return { Boolean } 返回是否是pc
*/
const JudgePC = () => {
let userAgent
if (window && window.navigator) {
userAgent = window.navigator.userAgent;
} else {
return true;
}
const agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPod', 'iPad'];
for (let i = 0; i < agents.length; i++) {
if (userAgent.indexOf(agents[i]) >= 0) return false;
}
return true;
};
const isPc = JudgePC()
复制代码
对大小、偏移量、生成频率进行适配
const fsRange = isPc ? [20, 16] : [14, 6]
const fs = fsRange[0] + Math.round(Math.random() * fsRange[1])
const leftRange = isPc ? [-80, 80] : [-40, 40]
const endLeft = emoteParams.left + leftRange[Math.round(Math.random())]
let num = 0
const start = () => setInterval(() => {
if (num % 6 === 0) {
setInnerSize()
isPc = JudgePC()
}
num += 1
setEmoteAnimate()
}, isPc ? 320 : 540)
复制代码
适配背景图
@media only screen and (max-width: 768px) {
body {
background: url("../img/bg-mobile.png") center no-repeat;
background-size: cover;
}
}
复制代码
码上掘金
这是第一篇技术文,也是正式踏上开源路上的开始。万事开头难,我的第一步足足用了两年。
余音
新春将至,祝大家幸福安康,阖家团圆,把酒言欢!欢迎大家一键三连~🙏🙏🙏