CSS实现文字跑马灯效果

在完成一个任务的时候,要求在表格中固定宽度的其中一个item文字过长需要滚动显示,然后经过多次效果的尝试,实现代码如下所示:

  • 它需要一个外层包围盒,设置定宽、文字不换行以及超过隐藏
  • 子元素为一个p标签,设置width: fit-content;使盒子背景宽度随文字宽度而进行自适应,并设置一个自定义属性text(可自定义)
  • p标签添加伪元素::after ,设置content: attr(text);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
		* {
			margin:0;
            padding: 0;
		}
		.container {
            /* 最外层盒子,需要三个属性:定宽、文字不换行、超过隐藏 */
			width: 500px;
			white-space: nowrap;
			overflow: hidden;
			font-size: 20px;
			color: #65b4ae;
		}
		.container_words {
			position: relative;
            /* 盒子背景宽度将随文字宽度而进行自适应 */
			width: fit-content;
            /* 添加动画 */
			animation: move 4s linear infinite;
            /* 让前面的几个文字有一个初始的距离,达到更好的呈现效果 */
            padding-left: 20px;
		}
		.container_words::after {
			position: absolute; 
			right: -100%;
			content: attr(text);
		}
		@keyframes move {
			0% {
				transform: translateX(0);
			}
			100% {
				transform: translateX(-100%);
			}
		}
	</style>
</head>
<body>
    <div class="container">
        <p class="container_words" text="文字文字文字文字文字">
            文字文字文字文字文字
        </p>
    </div>
</body>
</html>

效果如下:

在这里插入图片描述

那么,我们试着将其封装,以便在多处使用:

  • 首先,我们需要计算这段文字的宽度。通过扩展String原型方法getWidth
/**
 * 获取文本px宽度
 * @param font{String}: 字体样式
 * @return {Number} 文本宽度
 **/
String.prototype.getWidth = function (font: string) {
    // re-use canvas object for better performance
    const canvas =
            String.prototype.getWidth.canvas ||
            (String.prototype.getWidth.canvas = document.createElement('canvas')),
        context = canvas.getContext('2d');

    font && (context.font = font);
    const metrics = context.measureText(this);
    let width = metrics.width;
    if (props.letterSpacing && text && text.length > 1) {
        width = metrics.width + props.letterSpacing * text.length;
    }

    return width;
};

  • 其次,我们设想哪些参数是需要可配置的。
属性是否必须类型默认值描述
widthNumber-元素DOM的最大宽度,超过此宽度将滚动
textString-文本内容
fontString-这个是用来计算传入的文本的真实宽度,对比最大宽度看是否需要滚动。示例:21px SourceHanSansCN-Normal
classNamesString元素class类名,需要设置其他的样式
speedNumber20滚动速度,单位s
paddingLeftNumber20paddingLeft,需要滚动的元素的初始paddingLeft,为了防止初次滚动而看不见前面几个字
letterSpacingNumber0letterSpacing,文本字体之间间距

那么,封装的组件完整代码如下:

<template>
    <div
        v-if="text.getWidth(font) > width"
        :class="['horse', classNames]"
        :style="{
            width: width + 'px',
            '--speed': speed,
        }"
    >
        <p
            :text="text"
            class="horse_words"
            :style="{
                paddingLeft: paddingLeft + 'px',
            }"
        >
            {{ text }}
        </p>
    </div>
    <div
        v-else
        :style="{
            width: width + 'px',
        }"
        :class="classNames"
    >
        {{ text }}
    </div>
</template>

<script lang="ts">
export default {
    name: 'HorseRaceLamp',
    props: {
        // 元素DOM的最大宽度,超过此宽度将滚动
        width: {
            type: Number,
            required: true,
        },
        // 文本内容
        text: {
            type: String,
            required: true,
        },
        // 文本字体、大小等 示例:'21px SourceHanSansCN-Normal'
        font: {
            type: String,
            required: true,
        },
        // 元素class类名,需要设置其他的样式
        classNames: {
            type: String,
            default: '',
        },
        // 滚动速度,单位s
        speed: {
            type: Number,
            default: 20,
        },
        // paddingLeft,需要滚动的元素的初始paddingLeft,为了防止初次滚动而看不见前面几个字
        paddingLeft: {
            type: Number,
            default: 20,
        },
        // 文本字体之间间距
        letterSpacing: {
            type: Number,
            default: 0,
        },
    },
};
</script>

<style lang="scss" scoped>
.horse {
    white-space: nowrap;
    overflow: hidden;

    &_words {
        position: relative;
        width: fit-content;
        animation: move calc(var(--speed) * 1s) linear infinite;

        &::after {
            position: absolute;
            right: -100%;
            content: attr(text);
        }
    }
}
@keyframes move {
    0% {
        transform: translateX(0);
    }

    100% {
        transform: translateX(-100%);
    }
}
</style>

使用方式:

<HorseRaceLamp
    font="20px SourceHanSansCN-Normal"
    :width="115"
    text="今日累计收费金额今日累计收费金额今日累计收费金额"
/>
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐