123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- <template>
- <view class="notice-container" :style="{ padding: `0 ${gap}px` }">
- <view class="notice-wrapper">
- <view class="notice-icon">公告</view>
- <view class="notice-content">
- <swiper class="notice-swiper" vertical :circular="true" :autoplay="true" :interval="swiper * 1000" :duration="500" :display-multiple-items="1" @change="handleChange">
- <swiper-item v-for="(notice, index) in noticeList" :key="index" @click="handleNoticeClick(notice)">
- <view class="notice-item">{{ notice.text }}</view>
- </swiper-item>
- </swiper>
- <view class="notice-more">更多 ></view>
- </view>
- </view>
- </view>
- </template>
- <script setup>
- import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
- // 定义props
- const props = defineProps({
- noticeList: {
- type: Array,
- default: () => [],
- validator: (value) => {
- return value.every((item) => typeof item.text === 'string' && typeof item.url === 'string');
- },
- },
- gap: {
- type: Number,
- default: 0,
- },
- swiper: {
- type: Number,
- default: 3,
- },
- });
- // 响应式状态
- const currentIndex = ref(0);
- let timer = null;
- // 计算循环列表
- const displayList = computed(() => {
- return [props.noticeList[props.noticeList.length - 1], ...props.noticeList, props.noticeList[0]];
- });
- // 处理点击事件
- const handleNoticeClick = (notice) => {
- if (notice.url) {
- // window.location.href = notice.url;
- uni.navigateTo({
- url: notice.url,
- });
- }
- };
- // 启动轮播
- const startSwiper = () => {
- if (props.noticeList.length <= 1) return;
- // 设置初始位置
- currentIndex.value = 1;
- timer = setInterval(() => {
- const nextIndex = currentIndex.value + 1;
- if (nextIndex >= displayList.value.length - 1) {
- currentIndex.value = nextIndex;
- // 当到达最后一个元素时,等待过渡动画完成后重置到第一个元素
- setTimeout(() => {
- currentIndex.value = 1;
- }, 500);
- } else {
- currentIndex.value = nextIndex;
- }
- }, props.swiper * 1000);
- };
- // 监听列表变化
- watch(
- () => props.noticeList.length,
- () => {
- if (timer) {
- clearInterval(timer);
- }
- startSwiper();
- }
- );
- // 组件挂载时启动轮播
- onMounted(() => {
- startSwiper();
- });
- // 组件卸载时清理定时器
- onUnmounted(() => {
- if (timer) {
- clearInterval(timer);
- }
- });
- </script>
- <style lang="less" scoped>
- .notice-container {
- margin: 4px 0;
- position: relative;
- .notice-wrapper {
- display: flex;
- align-items: center;
- height: 40px;
- background: #fff;
- border-radius: 130rpx 130rpx 130rpx 130rpx;
- }
- .notice-icon {
- width: 68rpx;
- height: 32rpx;
- color: #f89c33;
- font-size: 14px;
- border: 1px solid #f89c33;
- border-radius: 8rpx;
- text-align: center;
- line-height: 32rpx;
- margin: 0 10px;
- }
- .notice-content {
- flex: 1;
- height: 40px;
- overflow: hidden;
- }
- .notice-slider {
- height: 100%;
- }
- .notice-item {
- height: 40px;
- line-height: 40px;
- color: #333;
- font-size: 14px;
- cursor: pointer;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- width: 80%;
- }
- .notice-more {
- color: #999;
- position: absolute;
- right: 25px;
- top: 50%;
- transform: translateY(-50%);
- font-size: 12px;
- }
- }
- </style>
|