uniapp小程序沉浸式轮播图


发布于 2025-04-02 / 22 阅读 / 0 评论 /
引用页面 <template> <view> <view class="swiper-container"> <LlIndexSwiper :list="swiperList" /> <view class="black-bar" :style="{ top: statusBarH

引用页面

<template>
	<view>
		<view class="swiper-container">
			<LlIndexSwiper :list="swiperList" />
			<view class="black-bar" :style="{ top: statusBarHeight + 'px' }">
				<div class="nk" style="">第一排</div>
				<div class="sl" style="">第二排</div>
			</view>
		</view>
	</view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { LlIndexSwiper } from './ll-IndexSwiper.vue'

// 准备轮播图数据
const swiperList = ref([
	{
		src:"https://A5%BD%E5%9B%9B%E6%9C%88%E5%86%8D%E8%A7%81%E5%A4%A9%E7%A9%BA%E6%96%87%E8%89%BA%E9%A3%8E%E5%85%AC%E4%BC%97%E5%8F%B7%E5%B0%81%E9%9D%A2%20%281%29.jpg"
	},
	{
		src: 'https://d8%8A%B1%E8%8D%89%E5%9B%9B%E6%9C%88%E4%BD%A0%E5%A5%BD%E4%B8%89%E6%9C%88%E5%86%8D%E8%A7%81%E5%B0%81%E9%9D%A2%E9%A6%96%E5%9B%BE.jpg'
	},
	{
		src: 'https://daohaE7%BB%BF%E8%89%B2%E6%91%84%E5%BD%B1%E9%A3%8E%E7%AE%80%E7%BA%A6%E5%85%AC%E4%BC%97%E5%8F%B7%E9%A6%96%E5%9B%BE.jpg'
	},

])

// 添加状态栏高度的ref
const statusBarHeight = ref(0)

onMounted(() => {
	// 获取系统信息
	const systemInfo = uni.getSystemInfoSync()
	// 状态栏高度(px单位)
	statusBarHeight.value = systemInfo.statusBarHeight
})
</script>

<style lang="scss" scoped>
.swiper-container {
	position: relative;

	.black-bar {
		position: absolute;
		left: 0;
		width: 100%;
		height: 10px;
		z-index: 10;

		.nk {
			width: 570rpx;
			height: 80rpx;
			// background-color: aqua;
		}

		.sl {
			width: 100%;
			height: 80rpx;
			margin-top: 5rpx;
			// background-color: green;
		}
	}


}
</style>

轮播图组件ll-IndexSwiper.vue

<template>
	<view class="swiper-page">
		<view class="bg_img_view">
			<image
				class="bg_img"
				v-for="(item,index) in props.list"
				:key="index"
				:src="item.src" 
				:style="{ zIndex : index === current ? '9' : '1' }"
				:class="{ 'fadein' : index === current }"
			/>
		</view>
		<swiper
			class="swiper"
			id="swiper"
			:indicator-dots="false"
			:autoplay="true"
			:interval="5000"
			:duration="500"
			indicator-active-color="#5ca9b7"
			circular
			@change="onChange"
			@animationfinish="onAnimationfinish"
			@transition="onTransition"
		>
			<swiper-item v-for="(item,index) in props.list" :key="index">
				<view class="swiper-item">
					<image class="image" :style="{ top : `${top}px`, left: `${left}px` }" :src="item.src" mode=""></image>
				</view>
			</swiper-item>
		</swiper>
	</view>
</template>

<script setup>
	import { computed, getCurrentInstance, onMounted, reactive, ref } from 'vue';
	import { useThrottle } from './index.js';
	const { proxy } = getCurrentInstance()
	
	const props = defineProps({
		list: {
			type: Array,
			default: () => []
		}
	})
	const top = ref(0)
	const left = ref(0)
	const width = ref(0)
	const query = uni.createSelectorQuery().in(proxy);
	onMounted(() => {
		query.select('#swiper').boundingClientRect(data => {
		  // console.log("得到布局位置信息" + JSON.stringify(data));
		  // console.log("节点离页面顶部的距离为" + data.top);
		  top.value = data.top * -1
		  left.value = data.left * -1
		  width.value = data.width
		}).exec()
	})
	const current = ref(0)
	const bgImg = computed(() => {
		return props.list[current.value].src
	})
	const onAnimationfinish = (e) => {
		current.value = e.detail.current
		isRightScorll.value = false
		isLeftScorll.value = false
	}
	const onChange = () => {
		// console.log('变换了')
	}
	const isRightScorll = ref(false)
	const isLeftScorll = ref(false)
	const isShow = ref(true)
	const onTransition = useThrottle((e) => {
		if (e.detail.dx >= width.value * 0.5 && !isRightScorll.value) {
			startAni()
			if (current.value === props.list.length - 1) {
				current.value = 0
			} else {
				current.value++
			}
			isRightScorll.value = true
			isLeftScorll.value = false
		}
		if (e.detail.dx < width.value * 0.5 && isRightScorll.value) {
			startAni()
			if (current.value === 0) {
				current.value = props.list.length - 1
			} else {
				current.value--
			}
			isRightScorll.value = false
			isLeftScorll.value = false
		}
		if (e.detail.dx <= width.value * -0.5 && !isLeftScorll.value) {
			startAni()
			if (current.value === 0) {
				current.value = props.list.length - 1
			} else {
				current.value--
			}
			isLeftScorll.value = true
			isRightScorll.value = false
		}
		if (e.detail.dx > width.value * -0.5 && isLeftScorll.value) {
			startAni()
			if (current.value === props.list.length - 1) {
				current.value = 0
			} else {
				current.value++
			}
			isLeftScorll.value = false
			isRightScorll.value = false
		}
	}, 200)
	
	const opacity = ref(1)
	const startAni = () => {
		opacity.value = 0.3
		setTimeout(() => {
			opacity.value = 1
		}, 80)
	}
	const styles = {
		'width': '100vw',
		'height': '500rpx',
		'position': 'absolute',
		'inset': 0,
		'z-index': 1,
	}
	
	const dotsStyles = reactive({
		height: 2,
		backgroundColor: 'rgba(92, 169, 183, .3)',
		border: '1px rgba(92, 169, 183, .3) solid',
		color: '#fff',
		selectedBackgroundColor: 'rgba(92, 169, 183, .9)',
		selectedBorder: '1px rgba(92, 169, 183, .9) solid'
	})
</script>

<script>
	export default { name:"IndexSwiper" }
</script>

<style lang="scss">
.swiper-page {
	width: 100vw;
	height: 500rpx;
	display: flex;
	justify-content: center;
	background-size: cover;
	position: relative;
	.bg_img {
		width: 100vw;
		height: 500rpx;
		position: absolute;
		inset: 0;
		z-index: 1;
		opacity: 0;
		// opacity: v-bind('opacity');
		// transition: opacity 0.1s;
		-webkit-transition: all 0.2s;
		-moz-transition: all 0.2s;
		-ms-transition: all 0.2s;
		-o-transition: all 0.2s;
		transition: all 0.2s;
	}
	.fadein {
		opacity: 1 !important;
	}
	.swiper {
		margin-top: 136px;
		width: 650rpx;
		height: 200rpx;
		border-radius: 20rpx;
		overflow: hidden;
		position: relative;
		z-index: 18;
		.swiper-item {
			width: 100%;
			height: 100%;
			overflow: hidden;
			border-radius: 20rpx;
			position: relative;
			z-index: 4;
			.image {
				width: 100vw;
				height: 500rpx;
				position: absolute;
				z-index: 3;
			}
		}
	}
}

</style>

组件js

import { ref } from 'vue';

/**
 * 防抖
 * @param {Function} callback 函数
 * @param {number} delay 时间 ms
 * @return {Function} 回调
*/
export function useDebounce(callback, delay) {
  const timer = ref(null);

  function debounce(...args) {
    if (timer.value) {
      clearTimeout(timer.value);
    }
    timer.value = setTimeout(() => {
      callback(...args);
      timer.value = null;
    }, delay);
  }

  return debounce;
}

/**
 * 节流
 * @param {Function} fn  函数
 * @param {number} 时间 ms
 * @return {Function} 回调
*/
export function useThrottle(fn, delay) {
  const throttled = ref(false);
  
  return function(...args) {
    if (!throttled.value) {
      throttled.value = true;
      fn(...args);
      setTimeout(() => {
        throttled.value = false;
      }, delay);
    }
  };
}



是否对你有帮助?

评论