引用页面
<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);
}
};
}