带你实现花式的文字跃动与曲线效果,可不要掉队哦!
炫酷的效果背后所蕴含的往往是最深刻的编程思想和应用场景。
就像下面这个文字的跃动效果,你有没有实现思路呢?
大家好,我是渡一前端子辰老师,今天再来挑战一下你的编程能力吧
这种排列不仅适用与文字,任何元素的排列都可以把它做成更加丰富的形式。
我们来看一下这是怎么做的。
设计思路
完成这个效果,我们需要用到 JS 的函数来控制每个文字元素的位置和偏移量。
如果我们用 CSS 来做,就需要为每个文字元素单独设置样式,这样非常麻烦,而且如果文字内容发生变化,CSS 还得重新写。
我们首先思考第一个问题,就是你怎么告诉 JS,你要排列成什么样子。
这里就要捡一捡我们之前学过的曲线函数了:
比如这个曲线看上去是不是很眼熟?像不像正弦函数,一个正弦函数的曲线不就是这个样子吗。
那我们把曲线函数告诉 JS,然后再告诉 JS 一个截取范围,就是横坐标的取值范围:
还有没有别的要告诉 JS 呢?我们看图,截取范围是一个连续平滑的曲线,曲线上的点却是无限的。
但是我们排列的文字是有限的,那怎么办?
只能告诉 JS 点的数量了,比如我们告诉 JS 有 11 个点,那么这些点就应该在截取的范围内均匀排列:
现在我们告诉 JS 三个东西,还有什么东西呢?我们继续看。
图上的 x y 坐标它的值是在竖轴上的 x y 的坐标,而不是我们在页面呈现上的坐标系,所以说呢,我们要把它应用到页面上去的时候,在计算这个坐标点的时候,还要对它进行相应的缩放,比如说你的取值范围是 0 ~ 10,而页面上呢整个元素排列出来有 100 个像素,是不是 x 和 y 坐标都要放大 10 倍。
所以一共要告诉 JS 四个东西,函数本身以及取值范围和点的个数,还有整个排列元素的总宽度。
只要告诉 JS 这四个东西,是不是就可以把每一个点的 y 坐标给它算出来,y 坐标就是元素的偏移量,那剩下的事情就是去实现这个 JS 函数了。
这个函数子辰已经提前实现了。
首先我们定义一个 getCurvePoints 函数,它接受四个参数:
- curveFunc 表示曲线函数;
- range 表示取值范围;
- number 表示点的数量;
- xLength 表示 x 的长度。
然后它返回一个数组,表示每个点在 y 轴上的偏移量:
/**
* 创建一个曲线,得到曲线上的均分散列点
* @param {(number)=>number} curveFunc:曲线函数
* @param {[number, number]} range:取值范围
* @param {number} number:点的数量
* @param {number} xLength:x 的长度
* @returns
*/
function getCurvePoints(curveFunc, range, number, xLength) {
if (number < 1) {
return [];
}
if (number === 1) {
return [0];
}
const piece = (range[1] - range[0]) / (number - 1);
const result = [];
const scale = xLength / (range[1] - range[0]);
for (let i = 0; i < number; i++) {
result.push(-curveFunc(i * piece + range[0]) * scale);
}
return result;
}
函数代码也没几行,函数一共接收四个参数,就是我们刚才说的四个参数了,这个函数就能帮我们计算出每一个点的 y 坐标了,也就是偏移量。
这个函数有兴趣的同学可以自己写一下,非常的简单,也可以拿子辰的代码去参考一下。
代码实现
我们在控制台中直接使用一下 getCurvePoints 函数并传入参数,看看效果:
可以看到 getCurvePoints 函数给我们返回了 20 个点的纵向坐标了,到时候把元素按照这个纵坐标去排列,是不是就可以了。
我们去具体写一下。
// 首先拿到我们整个的容器
const container = document.querySelector(".container");
// 目前我们的容器里都是文字,所以我们要将每一个文字拆开,生成一个元素
// 并覆盖掉原来的内容
container.innerHTML = container.textContent
.split("")
.map((l) => `<span>${l}</span>`)
.join("");
可以看到目前我们的容器里所有的文字,都变成了 span
元素,我们的第一步完成了。
接下来就是设置每一个 span
元素的位置了:
const container = document.querySelector(".container");
container.innerHTML = container.textContent
.split("")
.map((l) => `<span>${l}</span>`)
.join("");
// 写一个函数用来对 getCurvePoints 函数进行进一步的封装
/**
* @param {(number)=>number} func:曲线函数
* @param {[number, number]} range:取值范围
*/
function createCurve(func, range) {
// 在这里调用 getCurvePoints 函数,把曲线函数和取值范围传进去
// 多少个点就是 container 有多少个子元素 container.children.length,
// 第四个参数也就是 container 的宽度 container.clientWidth
// 这样子就得到了所有的点
const points = getCurvePoints(func, range, container.children.length, container.clientWidth);
// 循环每一个元素
for (let i = 0; i < points.length; i++) {
// 找到对应的子元素,改变子元素的 y 偏移量
container.children[i].style.transform = `translateY(${points[i]}px)`;
}
}
createCurve((x) => Math.sin(x), [0, 2 * Math.PI]);
可以看到效果已经出来了。
这种写法灵活度非常高,它不像 CSS 是写死的,无论你里边是什么样的文字都无所谓,它都能正常的排列。
因为灵活度很高,所以我们还可以去改动它的取值范围,来实现滚动效果。
// 定一个偏移量
let offset = 0;
createCurve((x) => Math.sin(x), [offset, offset + 2 * Math.PI]);
setInterval(() => {
// 每间隔一段时间改变偏移量
offset += 0.1;
createCurve((x) => Math.sin(x), [offset, offset + 2 * Math.PI]);
}, 30);
可以看到动画已经实现了,是不是很简单?
总结
我们做效果的时候要首先要把这个东西想通,你打算怎么做,怎么做逻辑是通的,然后再去具体实现代码,好的思考是避坑的前提,也是效率的前提,更是我们未来发展的前提。
这是一个很好的编程练习,也是一个很有用的技巧。
在未来的开发中,类似这样的文字排列效果会经常用到,特别是在需要给网页增加一些动态和个性的场景下,比如制作一个个人主页、一个博客、一个广告等等。
文章所实现的文字排列不仅仅是一个看起来很酷的效果,它背后所蕴含的是深刻的编程思想和应用场景。
本文来源
本文来源自渡一官方公众号:Duing,欢迎关注,获取最新、最全、最深入的技术讲解
感谢你阅读本文,如果你有任何疑问或建议,请在评论区留言,如果你觉得这篇文章有用,请点赞收藏或分享给你的朋友!
转载自:https://juejin.cn/post/7249386837369028663