创建滚动轮播组件实现超标信息自动滚动
为了实现超出父容器高度时的自动轮播滚动效果,我们可以创建一个通用的滚动组件,通过插槽来包裹内容。
1. 组件代码如下
vue:/Users/dylan/Documents/GitHub/Supervision-of-cooking-fume/src/components/ScrollList.vue
<template>
<div
ref="container"
class="scroll-container"
:style="{ height: height }"
@mouseenter="pauseScroll"
@mouseleave="resumeScroll"
>
<div
ref="wrapper"
class="scroll-wrapper"
:class="{ 'scrolling': isScrolling }"
:style="{ animationDuration: `${duration}s`, animationPlayState: isPaused ? 'paused' : 'running' }"
>
<slot></slot>
<!-- 当内容超出时,复制一份内容用于无缝滚动 -->
<div v-if="needScroll" class="scroll-duplicate">
<slot></slot>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue';
const props = defineProps({
// 容器高度
height: {
type: String,
default: '100%'
},
// 滚动速度,单位秒
duration: {
type: Number,
default: 20
},
// 是否自动开始滚动
autoScroll: {
type: Boolean,
default: true
},
// 滚动延迟,单位毫秒
delay: {
type: Number,
default: 500
}
});
const container = ref(null);
const wrapper = ref(null);
const isScrolling = ref(false);
const isPaused = ref(!props.autoScroll);
const needScroll = ref(false);
// 检查是否需要滚动
const checkNeedScroll = async () => {
await nextTick();
if (!container.value || !wrapper.value) return;
const containerHeight = container.value.clientHeight;
const contentHeight = wrapper.value.scrollHeight / (needScroll.value ? 2 : 1);
needScroll.value = contentHeight > containerHeight;
if (needScroll.value && props.autoScroll) {
startScroll();
} else {
stopScroll();
}
};
// 开始滚动
const startScroll = () => {
isScrolling.value = true;
isPaused.value = false;
};
// 停止滚动
const stopScroll = () => {
isScrolling.value = false;
};
// 暂停滚动
const pauseScroll = () => {
isPaused.value = true;
};
// 恢复滚动
const resumeScroll = () => {
if (needScroll.value) {
isPaused.value = false;
}
};
// 监听内容变化
const observer = ref(null);
onMounted(() => {
// 初始检查
setTimeout(checkNeedScroll, props.delay);
// 监听内容变化
if (window.MutationObserver) {
observer.value = new MutationObserver(checkNeedScroll);
if (wrapper.value) {
observer.value.observe(wrapper.value, {
childList: true,
subtree: true,
characterData: true
});
}
}
// 监听窗口大小变化
window.addEventListener('resize', checkNeedScroll);
});
onUnmounted(() => {
if (observer.value) {
observer.value.disconnect();
}
window.removeEventListener('resize', checkNeedScroll);
});
// 监听props变化
watch(() => props.autoScroll, (newVal) => {
isPaused.value = !newVal;
});
// 暴露方法给父组件
defineExpose({
checkNeedScroll,
startScroll,
stopScroll,
pauseScroll,
resumeScroll
});
</script>
<style scoped>
.scroll-container {
overflow: hidden;
position: relative;
width: 100%;
}
.scroll-wrapper {
position: relative;
width: 100%;
}
.scrolling {
animation: scrollAnimation linear infinite;
}
@keyframes scrollAnimation {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-50%);
}
}
.scroll-duplicate {
/* 确保复制的内容样式与原内容一致 */
}
</style>
2. 使用示例
vue:/Users/dylan/Documents/GitHub/Supervision-of-cooking-fume/src/views/IndexView.vue
<script setup>
import { ref, onMounted, onUnmounted, inject } from "vue";
// 导入依赖...
import ScrollList from "@/components/ScrollList.vue"; // 导入滚动组件
// 其他代码...
</script>
<template>
<div>
<ScrollList
class="flex-1 w-full hide-scrollbar"
:duration="30"
>
<div
v-for="(item, index) in 100"
:key="index"
>
{{item}}
</div>
</ScrollList>
</div>
</template>
组件功能说明
-
自动检测:组件会自动检测内容是否超出容器高度,只有超出时才会启动滚动
-
无缝滚动:通过复制一份内容实现无缝循环滚动效果
-
交互控制:鼠标悬停时暂停滚动,移出时恢复滚动
-
可配置性:
height
:设置容器高度duration
:控制滚动速度autoScroll
:是否自动开始滚动delay
:初始检测延迟时间
-
响应式:
- 监听内容变化自动更新滚动状态
- 监听窗口大小变化重新计算是否需要滚动
这个组件设计为通用组件,可以在项目中的其他需要滚动展示的地方复用,提高代码的可维护性和一致性。