分享一个简单但功能完整的雪花动画的实现,这个类可以轻松地在网页中添加飘雪效果,支持替换图片以实现其他飘落效果。
功能概述
这个雪花动画具有以下特性:
- 可控制雪花数量(最多30个)
- 可调节雪花飘落速度
- 随机雪花大小、透明度和初始位置
- 提供暂停和继续动画的方法
效果
代码解析
构造函数与初始化
constructor ({dom , speed, imageUrl, createrTime = 1000, number}) {
this.boxDom = dom
this.speed = speed > 0 && speed <= 100 ? speed / 10 : 5
this.imageUrl = imageUrl
this.number = number > 30 ? 30 : number
this.createrTime = createrTime
this.docWidth = document.documentElement.clientWidth || document.body.clientWidth
this.docHeight = document.documentElement.clientHeight || document.body.clientHeight
this.xueHuaList = []
this.moveTop = null
this.minOpacity=0.8
this.maxOpacity=1
this.minScale=0.3
this.maxScale=0.6
this.init()
}
构造函数接收配置参数并进行合理化处理,确保动画性能与视觉效果平衡。
雪花DOM创建与样式设置
createrXueHuaDom () {
let xueHuaImg = new Image()
xueHuaImg.src = this.imageUrl
xueHuaImg.style.position = 'absolute'
xueHuaImg.style.zIndex = '100000'
xueHuaImg.onload = () => {
this.xueHuaSize(xueHuaImg)
this.xueHuaPosition(xueHuaImg)
this.xueHuaOpacity(xueHuaImg)
this.boxDom.appendChild(xueHuaImg)
}
return xueHuaImg
}
创建雪花图片元素并设置基本样式,确保图片加载完成后进行尺寸、位置和透明度的随机设置。
动画核心逻辑
moveXueHua () {
this.moveXueHuaFn = setInterval(() => {
this.xueHuaList.forEach(item => {
item.img.style.top = `${item.img.offsetTop + item.moveTop}px`
if (this.docHeight + 100 < item.img.offsetTop) {
this.xueHuaSize(item.img)
this.xueHuaPosition(item.img)
this.xueHuaOpacity(item.img)
this.moveTop = +(Math.random() * (this.speed - 1) + 1).toFixed(2)
item.moveTop = this.moveTop
}
})
}, 50)
}
通过定时器实现雪花下落动画,当雪花飘出视窗后重置其位置和属性,实现循环效果。
使用示例
// 创建雪花动画实例
const snow = new XueHuaAnimation({
dom: document.getElementById('snow-container'),
speed: 30, // 速度范围1-100
imageUrl: require('snowflake.png'),
number: 20, // 雪花数量,最大30
createrTime: 1000 // 创建间隔
})
// 暂停动画
// snow.stopXueHua()
// 继续动画
// snow.continueXueHua()
完整代码
class XueHuaAnimation {
constructor ({dom , speed, imageUrl, createrTime = 1000, number}) {
this.boxDom = dom
this.speed = speed > 0 && speed <= 100 ? speed / 10 : 5
this.imageUrl = imageUrl
this.number = number > 30 ? 30 : number
this.createrTime = createrTime
this.docWidth = document.documentElement.clientWidth || document.body.clientWidth
this.docHeight = document.documentElement.clientHeight || document.body.clientHeight
this.xueHuaList = []
this.moveTop = null
this.minOpacity=0.8
this.maxOpacity=1
this.minScale=0.3
this.maxScale=0.6
this.init()
}
init () {
this.boxDom.style.position = 'fixed'
this.boxDom.style.zIndex = 10000
for(let i = 0; i < this.number; i++) {
this.moveTop = +(Math.random() * (this.speed - 1) + 1).toFixed(2)
this.xueHuaList.push({
img: this.createrXueHuaDom(),
moveTop: this.moveTop
})
}
this.moveXueHua()
}
createrXueHuaDom () {
let xueHuaImg = new Image()
xueHuaImg.src = this.imageUrl
xueHuaImg.style.position = 'absolute'
xueHuaImg.style.zIndex = '100000'
xueHuaImg.onload = () => {
this.xueHuaSize(xueHuaImg)
this.xueHuaPosition(xueHuaImg)
this.xueHuaOpacity(xueHuaImg)
this.boxDom.appendChild(xueHuaImg)
}
return xueHuaImg
}
xueHuaSize (img) {
let lenght = +(Math.random() * (this.maxScale - this.minScale) + this.minScale).toFixed(2)
img.style.width = `${lenght}rem`
img.style.height = `${lenght}rem`
}
xueHuaPosition (img) {
let lenght = Math.floor(Math.random() * 10)
let topLenght = +(Math.random() * (10 - 2) + 2).toFixed(2)
img.style.top = `${-topLenght}rem`
img.style.left = `${lenght > 15 ? lenght - 20 : lenght}rem`
}
xueHuaOpacity (img) {
let opacity = +(Math.random() * (this.maxOpacity - this.minOpacity) + this.minOpacity).toFixed(2)
img.style.opacity = opacity.toFixed(2)
}
moveXueHua () {
this.moveXueHuaFn = setInterval(() => {
this.xueHuaList.forEach(item => {
item.img.style.top = `${item.img.offsetTop + item.moveTop}px`
if (this.docHeight + 100 < item.img.offsetTop) {
this.xueHuaSize(item.img)
this.xueHuaPosition(item.img)
this.xueHuaOpacity(item.img)
this.moveTop = +(Math.random() * (this.speed - 1) + 1).toFixed(2)
item.moveTop = this.moveTop
}
})
}, 50)
}
stopXueHua () {
window.clearInterval(this.moveXueHuaFn);
}
continueXueHua () {
this.moveXueHua()
}
}
export default XueHuaAnimation;