组件滚动通知只能实现简单的滚动效果,不能实现滚动内容中的字进行不同颜色的更改,下面实现一个无缝衔接的滚动动画,可以根据自己的需要进行艺术化的更改需要滚动的内容,也可以自定义更改滚动速度。
<template>
<view class="container">
<!-- 文字滚动条 -->
<view
v-for="(item, index) in scrollItems"
:key="'text-' + index"
class="scroll"
:style="{'--t': item.duration + 's'}"
>
<view class="scroll-row">
<text
v-for="(skill, i) in skills"
:key="i"
class="skill-tag"
@click="handleSkillClick(skill)"
>{{ skill }}</text>
</view>
<view class="scroll-row">
<text
v-for="(skill, i) in skills"
:key="i + 'copy'"
class="skill-tag"
@click="handleSkillClick(skill)"
>{{ skill }}</text>
</view>
</view>
<!-- 彩色方块滚动条 -->
<view class="scroll img-box" style="--t: 25s">
<view class="scroll-row">
<view
v-for="n in 9"
:key="n"
class="color-box"
:style="{'--r': (n-1)*40}"
@click="changeBoxColor(n)"
>{{ n }}</view>
</view>
<view class="scroll-row">
<view
v-for="n in 9"
:key="n + 'copy'"
class="color-box"
:style="{'--r': (n-1)*40}"
@click="changeBoxColor(n)"
>{{ n }}-1</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const skills = ref([
'HTML', 'CSS', 'JavaScript',
'Vue', 'React', 'Figma', 'Photoshop'
])
const scrollItems = ref([
{ duration: 20 },
{ duration: 30 },
{ duration: 10 },
{ duration: 35 }
])
const handleSkillClick = (skill) => {
uni.showToast({
title: `点击了: ${skill}`,
icon: 'none'
})
}
const changeBoxColor = (n) => {
// 在实际应用中,你可能需要找到对应的DOM元素来修改样式
// 这里只是演示点击事件
uni.showToast({
title: `点击了方块 ${n}`,
icon: 'none'
})
}
</script>
<style>
/* 基础样式 */
.container {
min-height: 100vh;
background-color: #222;
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20px;
}
/* 滚动容器 */
.scroll {
position: relative;
display: flex;
width: 700px;
overflow: hidden;
-webkit-mask-image: linear-gradient(90deg, transparent, #fff 20%, #fff 80%, transparent);
mask-image: linear-gradient(90deg, transparent, #fff 20%, #fff 80%, transparent);
margin: 15px 0;
}
/* 滚动行 */
.scroll-row {
white-space: nowrap;
will-change: transform;
}
/* 技能标签 */
.skill-tag {
display: inline-block;
margin: 10px;
padding: 8px 15px;
background-color: #333;
border-radius: 5px;
letter-spacing: 0.2em;
text-transform: uppercase;
transition: all 0.3s ease;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.skill-tag:active {
background-color: #4caf50;
transform: scale(1.05);
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
}
/* 彩色方块 */
.img-box {
display: flex;
column-gap: 10px;
}
.color-box {
width: 150px;
height: 150px;
background-color: #ff3e3e;
filter: hue-rotate(calc(var(--r) * 1deg));
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
font-size: 1.5em;
border-radius: 8px;
margin: 0 10px;
transition: all 0.5s ease;
}
.color-box:active {
transform: rotate(15deg) scale(1.1);
box-shadow: 0 8px 16px rgba(0,0,0,0.3);
}
/* 动画效果 */
.scroll-row:first-child {
animation: animate var(--t) linear infinite;
animation-delay: calc(var(--t) * -1);
}
.scroll-row:nth-child(2) {
animation: animate2 var(--t) linear infinite;
animation-delay: calc(var(--t) / -2);
}
@keyframes animate {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
@keyframes animate2 {
0% { transform: translateX(0); }
100% { transform: translateX(-200%); }
}
/* 响应式设计 */
@media screen and (max-width: 768px) {
.scroll {
width: 95vw;
}
.skill-tag {
padding: 5px 10px;
font-size: 0.8em;
}
.color-box {
width: 20vw;
height: 20vw;
font-size: 1em;
}
}
</style>