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;
};
- 其次,我们设想哪些参数是需要可配置的。
属性 | 是否必须 | 类型 | 默认值 | 描述 |
---|---|---|---|---|
width | 是 | Number | - | 元素DOM的最大宽度,超过此宽度将滚动 |
text | 是 | String | - | 文本内容 |
font | 是 | String | - | 这个是用来计算传入的文本的真实宽度,对比最大宽度看是否需要滚动。示例:21px SourceHanSansCN-Normal |
classNames | 否 | String | 空 | 元素class类名,需要设置其他的样式 |
speed | 否 | Number | 20 | 滚动速度,单位s |
paddingLeft | 否 | Number | 20 | paddingLeft,需要滚动的元素的初始paddingLeft,为了防止初次滚动而看不见前面几个字 |
letterSpacing | 否 | Number | 0 | letterSpacing,文本字体之间间距 |
那么,封装的组件完整代码如下:
<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="今日累计收费金额今日累计收费金额今日累计收费金额"
/>