html、css、js、react、vue 文字一行一行显示出来
年报好帮手
前端时间在做 年报,就不难涉及到 年报 具有的几大特性:
1、页面滑动特效
2、文字一行一行出现特效
3、页面内动画
等等
这片文章主要展示一下 文字一行一行出现特效 代码(react 为例)
先看效果图:
第一步:分析
想要使 文字一行一行显示出来 无非就三种方式
1、使用css控制:底层一个完整页面,上层一个只有背景图的完整页面,通过动画渐渐向下移动上层div,使底层div信息逐渐展示出来,以达到渐显的效果,但视觉效果较差。
2、使用js控制:使用js逐步增加dom节点,并给dom节点添加动画效果。(对于React,Vue这类框架层面应用,不建议直接使用JS控制 DOM 节点增删)
3、js + css控制:初次页面全部渲染出来,并给每一行增加 id 属性,但Css样式为 opacity: 0 透明,渲染完成后,通过js改变 css 动画 样式。(本文所采用方式)
第二部:布局
1、想要使文字一行一行展示出来,我们期望的是得到渲染数组,这样才能对顺序进行控制。不同段落之间我们也期望 从上往下的段落一行一行展示出来,所以我们期望得到一个二位数组,like this:
funfunction Text(props) {
return <div>props?.text</div>
}
paragraphArrays : [
[
<Text text="第一段第一行" />,
<Text text="第一段第二行" />,
<Text text="第一段第三行" />,
],
[
<Text text="第二段第一行" />,
<Text text="第二段第二行" />,
<Text text="第二段第三行" />,
],
]
2、不同页面的文本承载container样式可能不同,所以我们期望使用者可自定义样式。
3、不同页面段落之间的样式可能不同,所以我们期望使用者可自定义样式。
4、使用者可自定义行 id
这样,动画组件的 props 我们就定义好了
第三部:实现
1、渲染函数:
js:
import React, { useEffect } from 'react'
import classnames from 'classnames'
import styles from './AnimationText.module.scss'
/**
* @description: 文字段落一行一行出现动画
* @param props:
* paragraphArrays : [
[
<Text text="第一段第一行" />,
<Text text="第一段第二行" />,
<Text text="第一段第三行" />,
],
[
<Text text="第二段第一行" />,
<Text text="第二段第二行" />,
<Text text="第二段第三行" />,
],
]
* paragraphClassName: 段落className
* className: container className
* id: container id
* @return {*}
*/
function AnimationText(props) {
const { paragraphArrays, paragraphClassName, className, id } = props || {}
return (
<div className={classnames(styles.container, className)} id={id || 'animationText'} >
{(paragraphArrays || []).map((item, index) => (
<div className={classnames(styles.paragraph, paragraphClassName)}>
{(item || []).map((component, idx) => (
<div id={`${index}-${idx}-${id || 'animationText'}`} className={styles.nodeItem} >
{component}
</div>
))}
</div>
))}
</div>
)
}
export default AnimationText
css:
.paragraph {
margin-bottom: 15px;
}
.nodeItem {
opacity: 0;
}
2、获取 container DOM 节点
// 用于存储 存放动画的 container
let element
// 等同于 componentDidMount
useEffect(() => {
element = document.getElementById(id || 'animationText')
}, [])
3、获取到DOM节点后, 开始执行动画
css 动画定义:
// 透明度从0 到 1,动画只执行一次
.nodeItemShow {
visibility: visible;
animation: scan 3s ease 0s 1;
}
@keyframes scan {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
js:
// 获取到 element 后,循环 paragraphArrays 数组,使用count 计数,每隔 600 * count 毫秒改变当前count 行的 css 样式
useEffect(() => {
if (element) {
let count = 0
for (let i = 0; i < paragraphArrays.length; i += 1) {
for (let j = 0; j < paragraphArrays[i].length; j += 1) {
count += 1
setTimeout(() => {
const ele = document.getElementById(`${i}-${j}-${id || 'animationText'}`)
ele.setAttribute('class', styles.nodeItemShow)
}, 600 * count)
}
}
}
}, [element])
完整代码:
js:
import React, { useEffect } from 'react'
import classnames from 'classnames'
import styles from './AnimationText.module.scss'
/**
* @description: 文字段落一行一行出现动画
* @param props:
* paragraphArrays : [
[
<Text text="第一段第一行" />,
<Text text="第一段第二行" />,
<Text text="第一段第三行" />,
],
[
<Text text="第二段第一行" />,
<Text text="第二段第二行" />,
<Text text="第二段第三行" />,
],
]
* paragraphClassName: 段落className
* className: container className
* id: container id
* @return {*}
*/
function AnimationText(props) {
const { paragraphArrays, paragraphClassName, className, id } = props || {}
let element
useEffect(() => {
element = document.getElementById(id || 'animationText')
}, [id])
useEffect(() => {
if (element) {
let count = 0
for (let i = 0; i < paragraphArrays.length; i += 1) {
for (let j = 0; j < paragraphArrays[i].length; j += 1) {
count += 1
setTimeout(() => {
const ele = document.getElementById(`${i}-${j}-${id || 'animationText'}`)
ele.setAttribute('class', styles.nodeItemShow)
}, 600 * count)
}
}
}
}, [element, id, paragraphArrays ])
return (
<div className={classnames(styles.container, className)} id={id || 'animationText'} >
{(paragraphArrays || []).map((item, index) => (
<div className={classnames(styles.paragraph, paragraphClassName)}>
{(item || []).map((component, idx) => (
<div key={`${index}-${idx}-${id || 'animationText'}`} id={`${index}-${idx}-${id || 'animationText'}`} className={styles.nodeItem} >
{component}
</div>
))}
</div>
))}
</div>
)
}
export default AnimationText
css:
.container {
width: auto;
}
.paragraph {
margin-bottom: 15px;
}
.nodeItem {
opacity: 0;
}
.nodeItemShow {
visibility: visible;
animation: scan 3s ease 0s 1;
}
@keyframes scan {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
一个简单的 文字一行一行显示出来 动画组件就实现啦
更多推荐
所有评论(0)