根据数据长度动态设定元素的animation
先看看效果,是一个纯原生div标签加上css实现的表格纵向滚动动画:
目录
- 根据数据长度动态设定元素的animation
- HTML
- js逻辑
- 1、判断是数据长度是否达到滚动要求
- 2、根据数据长度设置滚动速度
- Demo完整代码
HTML
1、确认好需要滚动内容的外盒子,并设置overflow: hidden;
2、类名为marquee的盒子为需要滚动内容的元素,给一个ref值之后通过获取ref设置元素的动画时长ref=“marqueeOld” ;
3、里面类名为row的子盒子是每行的表格内容
以下为控制台查看元素效果:
js逻辑
1、判断是数据长度是否达到滚动要求
滚动盒子的类绑定为 :class="{ ‘marquee’: shouldAnimate },在类名marquee 里给动画效果。以下为样式代码:
.marquee {
/* infinite永久调用动画 */
animation: material 300s linear infinite;
}
为了在计算属性中监听tableData数据的变化,若shouldAnimate返回为true,则有滚动marquee类名,否则不可滚动
可选链操作符 ? :在 JavaScript 中,当我们尝试访问一个对象的属性时,如果该对象为 null 或 undefined,通常会导致错误。可选链操作符 ? 可解决这一问题
这种写法可以让我们在访问对象的属性时更加安全,避免了因为对象不存在而导致的错误。特别是在处理来自外部或异步源的数据时,使用可选链操作符可以提高代码的健壮性。
computed: {
shouldAnimate () {
console.log("tableData.length >= 6", this.tableData.length >= 6);//若数据大于等于6条,则返回true;反之为false
return this.tableData?.length >= 6; //这个?号是可选链操作符
}
},
2、根据数据长度设置滚动速度
通过 refs 访问 DOM 元素时,有时需要在 DOM 渲染完成后才能正确获取到相应的元素,所以需要将设置滚动速度的逻辑放到 this.$nextTick 中,以确保 DOM 渲染完成后再进行操作,若没有nextTick 方法会找不到DOM,输出元素为undefined。
setMarqueeSpeed () {
if (this.shouldAnimate) {
this.$nextTick(() => {
// 根据数据长度设置滚动速度
this.$refs.marqueeOld.style.animationDuration = this.tableData.length * 2 + "s";
console.log("this.$refs.marqueeOld.style.animationDuration", this.$refs.marqueeOld.style.animationDuration);
});
}
}
.style.animationDuration 是一个 DOM 元素的属性,用于设置或获取元素应用的动画持续时间。在这里的情况下,想要根据数据长度动态地设置滚动速度,使用 .style.animationDuration 就可以实现这一目的。
当设置 .style.animationDuration 时,可以为其赋予一个字符串数值,表示动画的持续时间。例如
element.style.animationDuration = “2s” 表示将动画持续时间设置为 2 秒。
所以通过动态设置 .style.animationDuration,可以根据数据的长度来调整滚动速度,从而实现动态的滚动效果。控制台输出animationDuration如下:
Demo完整代码
import jsondata from ‘./test.json’;
其中jsondata 为自己配置的数据,若是从接口获取,在获取数据那里调用setMarqueeSpeed方法即可
<template>
<div class="innercolumn panel oldmaterial">
<div class="inner"
style="height: 100%">
<h3><i class="icon-table"></i> 表格标题</h3>
<div class="content"
style="display: block">
<div class="head headv1">
<span class="col text-center">ID</span>
<span class="col text-center">内容1</span>
<span class="col text-center">内容2</span>
<span class="col text-center">内容3</span>
<span class="col text-right">内容4</span>
</div>
<div class="marquee-view">
<div :class="{ 'marquee': shouldAnimate }"
ref="marqueeOld"
v-if="tableData">
<div class="row"
v-for="(item, index) in tableData"
:key="index">
<span class="col text-center nowrap">{{ item.ID }} </span>
<span class="col text-center nowrap">{{ item.name1 }} </span>
<span class="col text-center nowrap">{{ item.name2 }} </span>
<span class="col text-center nowrap">{{ item.name3 }} </span>
<span class="col text-right nowrap">{{ item.name4 }} </span>
<span class="icon-location"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import jsondata from './test.json';
export default {
data () {
return {
tableData: jsondata
};
},
created () { },
computed: {
shouldAnimate () {
console.log("tableData.length >= 6", this.tableData.length >= 6);
return this.tableData.length >= 6;
}
},
mounted () {
this.setMarqueeSpeed();
},
methods: {
setMarqueeSpeed () {
if (this.shouldAnimate) {
this.$nextTick(() => {
// 根据数据长度设置滚动速度
this.$refs.marqueeOld.style.animationDuration = this.tableData.length * 2 + "s";
console.log("this.$refs.marqueeOld.style.animationDuration", this.$refs.marqueeOld.style.animationDuration);
});
}
}
},
};
</script>
<style scoped>
.oldmaterial {
height: 17rem;
background: #080866;
color: #fff;
padding: 1rem;
width: 25%;
}
.oldmaterial .inner {
/* padding: 1rem 0; */
display: flex;
flex-direction: column;
}
.oldmaterial .tabs {
padding: 0 1.5rem;
margin-bottom: 0.75rem;
}
.oldmaterial .tabs a {
color: #1950c4;
font-size: 0.75rem;
padding: 0 1.125rem;
}
.oldmaterial .tabs a:first-child {
padding-left: 0;
}
.oldmaterial .tabs a.active {
color: #fff;
}
.oldmaterial .content {
flex: 1;
display: none;
position: relative;
}
.oldmaterial .head {
background: rgba(255, 255, 255, 0.1);
font-size: 13px;
padding: 0.5rem 0.5rem;
color: #68d8fe;
display: flex;
justify-content: space-between;
line-height: 1.05;
}
.oldmaterial .col {
width: 4rem;
}
.oldmaterial .row {
line-height: 1.05;
padding: 0.5rem 0.5rem;
color: #5b9cef;
font-size: 1rem;
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
}
.oldmaterial .icon-location {
position: absolute;
left: -0.1rem;
opacity: 0;
}
.oldmaterial .marquee-view {
position: absolute;
top: 2.4rem;
bottom: 0;
width: 100%;
overflow: hidden;
}
.oldmaterial .row:hover {
color: #5b9cef;
background: rgba(255, 255, 255, 0.1);
}
.oldmaterial .row:hover .icon-location {
opacity: 1;
}
@keyframes material {
0% {
}
100% {
transform: translateY(-50%);
}
}
/* 调用动画 */
.oldmaterial .marquee {
/* infinite永久调用动画 */
animation: material 300s linear infinite;
}
/* 鼠标划入 停止动画 */
.oldmaterial .marquee:hover {
animation-play-state: paused;
}
</style>