圣诞
分析
定义了一个名为myLabels
的数组,其中包含了三个字符串元素,分别是“Merry Christmas”, “健健康康,平安喜乐”, “一定要站在你所热爱的世界里闪闪发光”。
代码
let myLabels = [
"Merry Christmas",
"健健康康,平安喜乐",
"一定要站在你所热爱的世界里闪闪发光",
];
分析
创建了一个<div>
元素,用于表示雪花,设置其样式为绝对定位,颜色为白色,并设置雪花字符为 “?”。
然后获取了页面的高度和宽度,用于确定雪花的起始和结束位置。
接下来,定义了生成一片雪花的毫秒数,以及一个定时器,定期生成一片雪花。
在每个定时器回调函数中,随机生成雪花的起始和结束位置、大小、持续时间、透明度等参数。
然后,克隆出一个雪花,并根据上述参数设置其样式,并插入到页面中。
接下来设置了一个一次性定时器,用于在雪花生成后一段时间后,修改雪花的样式,使其具有下落效果。
最后,在雪花落下后一段时间,再次设置一个定时器,将雪花从页面中删除。
代码
function snow() {
// 1、定义一片雪花模板
var flake = document.createElement("div");
// 雪花字符 ???????????
flake.innerHTML = "?";
flake.style.cssText = "position:absolute;color:#fff;";
//获取页面的高度 相当于雪花下落结束时Y轴的位置
var documentHieght = window.innerHeight;
//获取页面的宽度,利用这个数来算出,雪花开始时left的值
var documentWidth = window.innerWidth;
//定义生成一片雪花的毫秒数
var millisec = 100;
//2、设置第一个定时器,周期性定时器,每隔一段时间(millisec)生成一片雪花;
setInterval(function () {
//页面加载之后,定时器就开始工作
//随机生成雪花下落 开始 时left的值,相当于开始时X轴的位置
var startLeft = Math.random() * documentWidth;
//随机生成雪花下落 结束 时left的值,相当于结束时X轴的位置
var endLeft = Math.random() * documentWidth;
//随机生成雪花大小
var flakeSize = 5 + 20 * Math.random();
//随机生成雪花下落持续时间
var durationTime = 4000 + 7000 * Math.random();
//随机生成雪花下落 开始 时的透明度
var startOpacity = 0.7 + 0.3 * Math.random();
//随机生成雪花下落 结束 时的透明度
var endOpacity = 0.2 + 0.2 * Math.random();
//克隆一个雪花模板
var cloneFlake = flake.cloneNode(true);
//第一次修改样式,定义克隆出来的雪花的样式
cloneFlake.style.cssText += `
left: ${startLeft}px;
opacity: ${startOpacity};
font-size:${flakeSize}px;
top:-25px;
transition:${durationTime}ms;
`;
//拼接到页面中
document.body.appendChild(cloneFlake);
//设置第二个定时器,一次性定时器,
//当第一个定时器生成雪花,并在页面上渲染出来后,修改雪花的样式,让雪花动起来;
setTimeout(function () {
//第二次修改样式
cloneFlake.style.cssText += `
left: ${endLeft}px;
top:${documentHieght}px;
opacity:${endOpacity};
`;
//4、设置第三个定时器,当雪花落下后,删除雪花。
setTimeout(function () {
cloneFlake.remove();
}, durationTime);
}, 0);
}, millisec);
}
调用函数
snow();
分析
使用MorphSVGPlugin插件来将指定的多边形转换为路径。
首先,调用MorphSVGPlugin.convertToPath("polygon")
方法,将ID为“polygon”的多边形元素转换为路径元素。
然后,定义了两个命名空间常量,xmlns
和xlinkns
,分别用于设置XML命名空间和Xlink命名空间。
接下来,定义了两个辅助函数select
和selectAll
,用于选择一个或多个元素。
然后,通过select
函数选择了一些DOM元素,例如.pContainer
、.mainSVG
、#star
、.sparkle
、#tree
等。
接下来,定义了一些变量,showParticle
为true
表示显示粒子,particleColorArray
是一个颜色数组,particleTypeArray
是一个粒子类型数组,用于指定粒子的形状。
然后,定义了一个粒子池数组particlePool
、一个粒子计数器particleCount
以及一个粒子数量numParticles
。
代码
MorphSVGPlugin.convertToPath("polygon");
var xmlns = "http://www.w3.org/2000/svg",
xlinkns = "http://www.w3.org/1999/xlink",
select = function (s) {
return document.querySelector(s);
},
selectAll = function (s) {
return document.querySelectorAll(s);
},
pContainer = select(".pContainer"),
mainSVG = select(".mainSVG"),
star = select("#star"),
sparkle = select(".sparkle"),
tree = select("#tree"),
showParticle = true,
particleColorArray = [
"#E8F6F8",
"#ACE8F8",
"#F6FBFE",
"#A2CBDC",
"#B74551",
"#5DBA72",
"#910B28",
"#910B28",
"#446D39",
],
particleTypeArray = ["#star", "#circ", "#cross", "#heart"],
// particleTypeArray = ['#star'],
particlePool = [],
particleCount = 0,
numParticles = 201;
分析
使用GSAP动画库(GreenSock Animation Platform)来操作SVG元素的动画效果。
首先,通过gsap.set
设置了SVG的可见性为“visible”,表示将SVG元素设置为可见状态。
接下来,使用gsap.set
设置了sparkle
元素的transformOrigin
为"50% 50%",并将其y坐标设置为-100,这将影响后续的动画效果。
然后定义了一个函数getSVGPoints
,用于获取SVG路径中的点坐标。该函数接受一个路径元素作为参数,通过MotionPathPlugin.getRawPath
方法获取路径的原始数据,并将其转换为点坐标的数组。
接着使用getSVGPoints
函数分别获取了.treePath
和.treeBottomPath
的点坐标,并存储在treePath
和treeBottomPath
变量中。
最后,创建了一个mainTl
的GSAP时间轴和一个starTl
的动画时间轴,用于控制整体的动画效果。
代码
// gsap动画库
gsap.set("svg", {
visibility: "visible",
});
gsap.set(sparkle, {
transformOrigin: "50% 50%",
y: -100,
});
let getSVGPoints = (path) => {
let arr = [];
var rawPath = MotionPathPlugin.getRawPath(path)[0];
rawPath.forEach((el, value) => {
let obj = {};
obj.x = rawPath[value * 2];
obj.y = rawPath[value * 2 + 1];
if (value % 2) {
arr.push(obj);
}
//console.log(value)
});
return arr;
};
let treePath = getSVGPoints(".treePath");
var treeBottomPath = getSVGPoints(".treeBottomPath");
//console.log(starPath.length)
var mainTl = gsap.timeline({ delay: 0, repeat: 0 }),
starTl;
分析
定义一个名为flicker
的函数,用于实现一个闪烁效果。
该函数接受一个参数p
,表示要应用闪烁效果的对象。
首先,通过gsap.killTweensOf
方法停止对象p
的所有关于透明度的动画效果。
然后,使用gsap.fromTo
方法设置对象p
的透明度动画效果。
初始状态下,设置透明度为1,即完全可见。
然后,设置动画的持续时间为0.07秒,并将透明度设置为一个随机值,范围在0到1之间。
最后,设置动画重复播放,使得闪烁效果无限循环。
代码
function flicker(p) {
//console.log("flivker")
gsap.killTweensOf(p, { opacity: true });
gsap.fromTo(
p,
{
opacity: 1,
},
{
duration: 0.07,
opacity: Math.random(),
repeat: -1,
}
);
}
分析
定义了一个名为createParticles
的函数,用于创建和初始化粒子(particles)。
首先,注释掉了变量step
的初始化代码和打印starPath.length
的语句。
接着,定义了变量i
,初始值为numParticles
。变量p
表示粒子的元素,particleTl
是粒子的动画时间轴,step
用于确定粒子在treePath
路径中的位置,pos
用于存储具体的粒子位置。
然后,使用while
循环逐个创建粒子对象。在每次循环中,通过select
方法选择一个粒子的类型,使用cloneNode(true)
方法对其进行克隆,并将克隆的粒子对象添加到mainSVG
中。
接下来,设置粒子的填充颜色,通过particleColorArray
数组来循环设置粒子的颜色属性。
然后,为粒子设置class
属性为particle
,并将其添加到particlePool
数组中,以便后续使用。
最后,使用gsap.set
方法将粒子对象的初始位置设置为(-100, -100),并设置transformOrigin
为"50% 50%"。
代码
function createParticles() {
//var step = numParticles/starPath.length;
//console.log(starPath.length)
var i = numParticles,
p,
particleTl,
step = numParticles / treePath.length,
pos;
while (--i > -1) {
p = select(particleTypeArray[i % particleTypeArray.length]).cloneNode(
true
);
mainSVG.appendChild(p);
p.setAttribute(
"fill",
particleColorArray[i % particleColorArray.length]
);
p.setAttribute("class", "particle");
particlePool.push(p);
//hide them initially
gsap.set(p, {
x: -100,
y: -100,
transformOrigin: "50% 50%",
});
}
}
分析
定义一个名为getScale
的函数,用于生成一个随机的缩放比例。该函数使用了gsap.utils.random
方法,传入了最小值0.5、最大值3、步长0.001和布尔值参数true。这意味着生成的随机数将在0.5到3之间,并以0.001为步长。
接下来,定义了一个名为playParticle
的函数,用于播放粒子动画。在函数内部,首先判断是否允许显示粒子,如果不允许,则直接返回。
然后,通过particlePool
数组获取当前要播放的粒子对象。
接下来,使用gsap.set
方法设置粒子的初始位置为.pContainer
元素的x和y属性的值,并设置缩放比例为通过getScale
函数生成的随机数。
然后,创建一个时间轴对象tl
,并使用tl.to
方法对粒子对象进行动画操作。
在动画过程中,设置了动画的持续时间为0.61到6秒之间的随机数。
使用physics2D
属性实现了一个物理引擎效果,具体的速度、角度和重力值通过gsap.utils.random
方法生成。
同时,设置了粒子的缩放比例和旋转角度为随机的范围值。
设置了动画的缓动函数为power1
。
在动画开始时调用了flicker
函数,并传入了粒子对象作为参数。
在动画重复时,通过onRepeat
方法设置了粒子的缩放比例为通过getScale
函数生成的随机数。
代码
var getScale = gsap.utils.random(0.5, 3, 0.001, true); // 圣诞树开始绘画时小光点动画的特效(参数:最小值,最大值,延迟)
function playParticle(p) {
if (!showParticle) {
return;
}
var p = particlePool[particleCount];
gsap.set(p, {
x: gsap.getProperty(".pContainer", "x"),
y: gsap.getProperty(".pContainer", "y"),
scale: getScale(),
});
var tl = gsap.timeline();
tl.to(p, {
duration: gsap.utils.random(0.61, 6),
physics2D: {
velocity: gsap.utils.random(-23, 23),
angle: gsap.utils.random(-180, 180),
gravity: gsap.utils.random(-6, 50),
},
scale: 0,
rotation: gsap.utils.random(-123, 360),
ease: "power1",
onStart: flicker,
onStartParams: [p],
//repeat:-1,
onRepeat: (p) => {
gsap.set(p, {
scale: getScale(),
});
},
onRepeatParams: [p],
});
//
//particlePool[particleCount].play();
particleCount++;
//mainTl.add(tl, i / 1.3)
particleCount = particleCount >= numParticles ? 0 : particleCount;
}
分析
定义一个名为drawStar
的函数,用于绘制星星动画。在函数内部,首先创建了一个时间轴对象starTl
,并设置了更新回调函数为playParticle
。
接下来,使用to
方法对.pContainer
和.sparkle
元素进行动画操作。在动画过程中,设置了动画的持续时间为6秒,并使用motionPath
属性指定了动画的路径为.treePath
元素,并禁用了自动旋转效果。设置了动画的缓动函数为linear
。
接着,使用to
方法对.pContainer
和.sparkle
元素进行动画操作。在动画开始时,通过onStart
函数将showParticle
变量设置为false
,表示不显示粒子。设置了动画的持续时间为1秒,并将元素的x和y属性设置为treeBottomPath[0].x
和treeBottomPath[0].y
。
然后,使用to
方法对.pContainer
和.sparkle
元素进行动画操作。在动画开始时,通过onStart
函数将showParticle
变量设置为true
,表示显示粒子。设置了动画的持续时间为2秒,并使用motionPath
属性指定了动画的路径为.treeBottomPath
元素,并禁用了自动旋转效果。设置了动画的缓动函数为linear
。
最后,使用from
方法对.treeBottomMask
元素进行动画操作。设置了动画的持续时间为2秒,并使用drawSVG
属性指定了路径的起始结束百分比为0% 0%
,即不显示路径,同时设置了画笔的颜色为#FFF
,表示白色。设置了动画的缓动函数为linear
。
代码
function drawStar() {
starTl = gsap.timeline({ onUpdate: playParticle });
starTl
.to(".pContainer, .sparkle", {
duration: 6,
motionPath: {
path: ".treePath",
autoRotate: false,
},
ease: "linear",
})
.to(".pContainer, .sparkle", {
duration: 1,
onStart: function () {
showParticle = false;
},
x: treeBottomPath[0].x,
y: treeBottomPath[0].y,
})
.to(
".pContainer, .sparkle",
{
duration: 2,
onStart: function () {
showParticle = true;
},
motionPath: {
path: ".treeBottomPath",
autoRotate: false,
},
ease: "linear",
},
"-=0"
)
// 圣诞树中间那条横线动画 .treeBottomMask 是绑定class='treeBottomMask'这个标签
.from(
".treeBottomMask",
{
duration: 2,
drawSVG: "0% 0%",
stroke: "#FFF",
ease: "linear",
},
"-=2"
);
//gsap.staggerTo(particlePool, 2, {})
}
分析
定义了一个名为drawMain
的函数,用于绘制主要的圣诞树动画。在函数内部,首先创建了一个时间轴对象mainTl
。
接下来,使用from
方法对.treePathMask
和.treePotMask
元素进行动画操作。设置了动画的持续时间为6秒,并使用drawSVG
属性指定了路径的起始结束百分比为0% 0%
,即不显示路径,同时设置了画笔的颜色为#FFF
表示白色。设置了动画的缓动函数为linear
。
然后,使用from
方法对.treeStar
元素进行动画操作。设置了动画的持续时间为3秒,并设置了元素的scaleY
属性为0、scaleX
属性为0.15,表示缩放比例,使用transformOrigin
属性指定了缩放的基点在元素的中心。设置了动画的缓动函数为elastic(1,0.5)
。
接着,使用to
方法对.sparkle
元素进行动画操作。设置了动画的持续时间为3秒,并将元素的透明度设置为0,使用了rough
缓动函数,该缓动函数会在动画期间以随机方式改变元素的透明度值。该动画将在前一个动画的结束点之后开始。
最后,使用to
方法对.treeStarOutline
元素进行动画操作。设置了动画的持续时间为1秒,并将元素的透明度设置为0.3,使用了rough
缓动函数,该缓动函数会在动画期间以随机方式改变元素的透明度值。该动画将在前一个动画的结束点之后开始。
代码
function drawMain() {
mainTl
// 圣诞树上半身轮廓动画
.from([".treePathMask", ".treePotMask"], {
duration: 6,
drawSVG: "0% 0%",
stroke: "#FFF",
stagger: {
each: 6,
},
duration: gsap.utils.wrap([6, 1, 2]),
ease: "linear",
})
// 圣诞树头上的星星动画
.from(
".treeStar",
{
duration: 3,
//skewY:270,
scaleY: 0,
scaleX: 0.15,
transformOrigin: "50% 50%",
ease: "elastic(1,0.5)",
},
"-=4"
)
// 当绘画圣诞树的小光点绘制完时,让小光点消失
.to(
".sparkle",
{
duration: 3,
opacity: 0,
ease: "rough({strength: 2, points: 100, template: linear, taper: both, randomize: true, clamp: false})",
},
"-=0"
)
// 给圣诞树头上的星星加个白色特效
.to(
".treeStarOutline",
{
duration: 1,
opacity: 0.3,
ease: "rough({strength: 2, points: 16, template: linear, taper: none, randomize: true, clamp: false})",
},
"+=1"
);
/* .to('.whole', {
opacity: 0
}, '+=2') */
}
分析
定义一个名为drawStars
的函数,用于绘制星星背景动画。在函数内部,首先获取了stars
元素,然后创建了一个canvas
元素并将其上下文赋给ctx
变量。接着,设置了canvas
的宽度和高度为窗口的宽度和高度,并分别赋给w
和h
变量。
然后,定义了一些变量,包括色调色彩hue
、保存星星对象的数组stars
、计数器count
和最大星星数量maxStars
。
接下来,创建了一个用于绘制星星的源图像canvas2
,并获取其上下文赋给ctx2
变量。设置了canvas2
的宽度和高度为100,并创建了径向渐变gradient2
,以半径为0的圆开始,到半径为half
的圆结束。根据色调色彩hue
的不同,设置了不同的颜色。然后,使用路径arc
创建了一个圆,并使用fill
方法填充了渐变。
接着,定义了一个random
函数,用于生成指定范围内的随机数。
定义了一个maxOrbit
函数,用于根据屏幕宽高计算星星的移动范围。
创建了一个Star
构造函数,用于实例化星星对象。在构造函数中,设置了星星的移动半径、大小、圆心位置、初始角度、移动速度和透明度等属性,并将新创建的星星对象存入stars
数组。
Star
对象定义了一个draw
方法,用于绘制星星。在该方法中,根据星星的移动半径和角度计算出星星在屏幕上的位置。根据随机数判断星星是否变亮或变暗,并根据透明度绘制星星。最后,更新星星的角度。
然后,使用循环创建了指定数量的星星对象。
最后,定义了一个animation
函数,用于执行星星的动画效果。在该函数中,首先绘制了一个半透明的背景颜色,然后使用for
循环调用每个星星对象的draw
方法进行绘制。最后,通过window.requestAnimationFrame
方法不断循环调用animation
函数,实现动画效果。
代码
function drawStars() {
let canvas = document.getElementById("stars"),
ctx = canvas.getContext("2d"),
w = (canvas.width = window.innerWidth),
h = (canvas.height = window.innerHeight),
hue = 37, //色调色彩
stars = [], //保存所有星星
count = 0, //用于计算星星
maxStars = 1300; //星星数量
//canvas2是用来创建星星的源图像,即母版,
//根据星星自身属性的大小来设置
var canvas2 = document.createElement("canvas"),
ctx2 = canvas2.getContext("2d");
canvas2.width = 100;
canvas2.height = 100;
//创建径向渐变,从坐标(half,half)半径为0的圆开始,
//到坐标为(half,half)半径为half的圆结束
var half = canvas2.width / 2,
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, "#CCC");
//hsl是另一种颜色的表示方式,
//h->hue,代表色调色彩,0为red,120为green,240为blue
//s->saturation,代表饱和度,0%-100%
//l->lightness,代表亮度,0%为black,100%位white
gradient2.addColorStop(0.1, "hsl(" + hue + ", 61%, 10%)");
gradient2.addColorStop(0.25, "hsl(" + hue + ", 64%, 2%)");
gradient2.addColorStop(1, "transparent");
ctx2.fillStyle = gradient2;
ctx2.beginPath();
ctx2.arc(half, half, half, 0, Math.PI * 2);
ctx2.fill();
// End cache
function random(min, max) {
if (arguments.length < 2) {
max = min;
min = 0;
}
if (min > max) {
var hold = max;
max = min;
min = hold;
}
//返回min和max之间的一个随机值
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function maxOrbit(x, y) {
var max = Math.max(x, y),
diameter = Math.round(Math.sqrt(max * max + max * max));
//星星移动范围,值越大范围越小,
return diameter / 2;
}
var Star = function () {
//星星移动的半径
this.orbitRadius = random(maxOrbit(w, h));
//星星大小,半径越小,星星也越小,即外面的星星会比较大
this.radius = random(60, this.orbitRadius) / 8;
//所有星星都是以屏幕的中心为圆心
this.orbitX = w / 2;
this.orbitY = h / 2;
//星星在旋转圆圈位置的角度,每次增加speed值的角度
//利用正弦余弦算出真正的x、y位置
this.timePassed = random(0, maxStars);
//星星移动速度
this.speed = random(this.orbitRadius) / 50000;
//星星图像的透明度
this.alpha = random(2, 10) / 10;
count++;
stars[count] = this;
};
Star.prototype.draw = function () {
//星星围绕在以屏幕中心为圆心,半径为orbitRadius的圆旋转
var x = Math.sin(this.timePassed) * this.orbitRadius + this.orbitX,
y = Math.cos(this.timePassed) * this.orbitRadius + this.orbitY,
twinkle = random(10);
//星星每次移动会有1/10的几率变亮或者变暗
if (twinkle === 1 && this.alpha > 0) {
//透明度降低,变暗
this.alpha -= 0.05;
} else if (twinkle === 2 && this.alpha < 1) {
//透明度升高,变亮
this.alpha += 0.05;
}
ctx.globalAlpha = this.alpha;
//使用canvas2作为源图像来创建星星,
//位置在x - this.radius / 2, y - this.radius / 2
//大小为 this.radius
ctx.drawImage(
canvas2,
x - this.radius / 2,
y - this.radius / 2,
this.radius,
this.radius
);
//没旋转一次,角度就会增加
this.timePassed += this.speed;
};
//初始化所有星星
for (var i = 0; i < maxStars; i++) {
new Star();
}
function animation() {
//以新图像覆盖已有图像的方式进行绘制背景颜色
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 0.9; //尾巴
ctx.fillStyle = "hsla(" + hue + ", 64%, 6%, 2)";
ctx.fillRect(0, 0, w, h);
//源图像和目标图像同时显示,重叠部分叠加颜色效果
ctx.globalCompositeOperation = "lighter";
for (var i = 1, l = stars.length; i < l; i++) {
stars[i].draw();
}
//调用该方法执行动画,并且在重绘的时候调用指定的函数来更新动画
//回调的次数通常是每秒60次
window.requestAnimationFrame(animation);
}
animation();
}
分析
执行了init
函数,接着依次执行了createParticles
、drawStar
、drawMain
和drawStars
等函数,并将它们添加到了mainTl
时间轴中。最后,通过gsap.globalTimeline.timeScale(1.5)
方法设置了全局时间轴的绘画速率。
代码
function init() {
let element = document.getElementById("header");
for(let i = 0; i < myLabels.length; i++) {
let _p = document.createElement("p");
_p.className = "header-item";
_p.innerHTML = myLabels[i];
element.appendChild(_p);
}
let labels = document.getElementsByClassName('header-item');
for(let i = 0; i < myLabels.length; i++) {
setTimeout(() => {
labels[i].classList.add("show");
}, 1000 * i);
}
}
init();
createParticles()
drawStar();
drawMain();
mainTl.add(starTl, 0);
gsap.globalTimeline.timeScale(1.5); // 圣诞树开始绘画时小光点动画的绘画速率,越大越快
drawStars();
大部分都是js代码,其实还有一些html和css需要自己研究一下,需要源码私信,祝大家平安夜圣诞夜快乐