我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!
前言
CSS + JS实现黏糊糊的文字变形效果,使用码上掘金查看实时效果
逻辑
初始化逻辑
const elts = {
text1: document.getElementById("text1"),
text2: document.getElementById("text2"),
};
// The strings to morph between. You can change these to anything you want!
const texts = ["Why", "is", "this", "so", "satisfying", "to", "watch?"];
// Controls the speed of morphing.
const morphTime = 1;
const cooldownTime = 0.25;
let textIndex = texts.length - 1;
let time = new Date();
let morph = 0;
let cooldown = cooldownTime;
elts.text1.textContent = texts[textIndex % texts.length];
elts.text2.textContent = texts[(textIndex + 1) % texts.length];
脚本初始化用elts保存了text1,text2对应的dom节点,
texts是要展示的文字变形数组,morphTime文件渐变的动画时间,cooldownTime文字动画冷却时间,设置text1显示的内容我WatchM?,text2的内容为Why
time记录初始化的时刻,morph记录渐变动画时间,cooldown保存动画冷却时间
animate
样式部分比较简单,主要讲解animate这个动画函数的效果
// Animation loop, which is called every frame.
function animate() {
requestAnimationFrame(animate);
let newTime = new Date();
let shouldIncrementIndex = cooldown > 0;
let dt = (newTime - time) / 1000;
time = newTime;
cooldown -= dt;
if (cooldown <= 0) {
if (shouldIncrementIndex) {
textIndex++;
}
doMorph();
} else {
doCooldown();
}
}
这是一个循环的动画,requestAnimationFrame这个api在每一帧渲染前都会执行一次
cooldown记录剩余的动画时间,每次执行animate和上一次的时间相减获得dt,cooldown = cooldown - dt,冷却时间小于等于0就执行渐变动画
冷却函数doCooldown,text2透明度100%,text1透明度为0,重置morph,filter为空
function doCooldown() {
morph = 0;
elts.text2.style.filter = "";
elts.text2.style.opacity = "100%";
elts.text1.style.filter = "";
elts.text1.style.opacity = "0%";
}
doMarph渐变动画前的判断,fraction为动画进行的百分比,当大于1说明渐变动画结束,回到动画冷却状态,fraction设置为1可以让渐变动画停止,我们可以看setMorch是根据fraction来设置filter的样式效果
function doMorph() {
morph -= cooldown;
cooldown = 0;
let fraction = morph / morphTime;
if (fraction > 1) {
cooldown = cooldownTime;
fraction = 1;
}
setMorph(fraction);
}
// A lot of the magic happens here, this is what applies the blur filter to the text.
function setMorph(fraction) {
// fraction = Math.cos(fraction * Math.PI) / -2 + .5;
elts.text2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
elts.text2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
fraction = 1 - fraction;
elts.text1.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
elts.text1.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
elts.text1.textContent = texts[textIndex % texts.length];
elts.text2.textContent = texts[(textIndex + 1) % texts.length];
}
总结
JS的逻辑很简单,主要在于filter和opacity的动画效果的计算方法,这个可以不断调整直到看起来最舒服的动画效果