<template>
<view class="container-scroll">
<!-- 文字导航 -->
<scroll-view class="scroll-view-text" scroll-x="true" v-if="type === 1">
<navigator
:url="item.url"
class="scroll-view-item"
:style="`width:${itemWidth}px`"
v-for="(item, index) in tarbarList"
:key="index"
>
<!-- 必须得多包一层 -->
<view class="text-container" :style="`width:${itemWidth}px`">
<view class="text-nav">
{{ item.title }}
</view>
</view>
</navigator>
</scroll-view>
<!-- 图文导航 -->
<scroll-view
class="img-scroll-view"
scroll-x="true"
@scroll="handleScroll"
ref="scrollView"
v-if="type === 2"
>
<view class="scroll-view-container">
<navigator
:url="item.url"
class="scroll-view-item"
:style="`width:${itemWidth}px`"
v-for="(item, index) in tarbarList"
:key="index"
>
<view class="nav-item">
<view class="image-container" :style="imageStyle">
<image
class="image"
:src="item.image"
mode="widthFix"
lazy-load="false"
:style="imageStyle"
>
</image>
</view>
<view class="text-title">
{{ item.title }}
</view>
</view>
</navigator>
</view>
</scroll-view>
</view>
<!-- 图文导航自定义滚动条 -->
<view
class="custom-scroll-container"
v-if="type === 2 && showNumber < tarbarList.length"
>
<view class="custom-scroll">
<view
class="scroll"
:style="`transform:translateX(${translateXValue}px)`"
/>
</view>
</view>
</template>
<script setup name="imageTextNavigator">
import { onMounted, ref, getCurrentInstance, computed } from "vue";
const props = defineProps({
type: {
// 1 图文导航 2 文字导航
type: Number,
default: 2,
},
// 首屏展示数量
showNumber: {
type: Number,
default: 4,
}, // 一屏显示的数量
tarbarList: {
type: Array,
default: () => [
{
title: "导航导航导航导航",
image: "",
url: "",
},
{
title: "导航导航导航导航",
image: "",
url: "",
},
{
title: "导航导航导航导航",
image: "",
url: "",
},
{
title: "导航导航导航导航",
image: "",
url: "",
},
{
title: "导航5",
image: "",
url: "",
},
{
title: "导航6",
image: "",
url: "",
},
],
},
});
const instance = getCurrentInstance();
// 活动距离
const translateXValue = ref(0);
const itemWidth = ref(0);
// 计算滚动距离
function handleScroll(event) {
// 30 滑块父盒子的宽度
// 8 滑块的宽度
// scrollLeft 是 scroll-view 滚动的距离
const scrollLeft = event.detail.scrollLeft; // 获取scroll-view滚动的距离
const scrollWidth = event.detail.scrollWidth; // 获取scroll-view内容的总宽度
const viewWidth = 375; // scroll-view的视口宽度
// 滑块父容器的宽度为30,滑块的宽度为8,计算出滑块可移动的最大距离
const maxTranslateX = 30 - 8; // 最大滑动距离 22
// 计算滚动条的移动比例,将内容滚动的比例映射到滑块的移动范围内
const moveRatio = maxTranslateX / (scrollWidth - viewWidth); // 滑块能够移动距离 比上 大容器能够滑动的距离,映射出 比率,最高就是 100% 嘛,等比换算
// 计算滑块的实际位置,确保不会超过最大移动距离
translateXValue.value = Math.min(scrollLeft * moveRatio, maxTranslateX);
}
// 图片样式
const imageStyle = computed(() => {
return {
width: props.showNumber === 4 ? `44px` : `36px`,
height: props.showNumber === 4 ? `44px` : `36px`,
};
});
function getElementInfo(id, context) {
return new Promise((resolve, reject) => {
let query = uni.createSelectorQuery().in(context);
query
.select(id)
.boundingClientRect((rect) => {
if (rect) {
// 获取的元素都是 px 需要乘以 2
resolve(rect);
} else {
reject();
}
})
.exec();
});
}
async function setNavItemWidth() {
const eleInfo = await getElementInfo(".container-scroll", instance);
const phoneWidth = eleInfo.width;
itemWidth.value = phoneWidth / props.showNumber;
}
onMounted(async () => {
await setNavItemWidth();
});
</script>
<style lang="scss" scoped>
.container-scroll {
width: 750rpx;
position: relative;
.scroll-view-text {
white-space: nowrap;
width: 750rpx;
display: flex;
.scroll-view-item {
display: inline-block;
background: #ffffff;
.text-container {
width: 150rpx;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.text-nav {
width: 112rpx;
font-weight: 400;
font-size: 28rpx;
color: #b2945e;
line-height: 28rpx;
font-style: normal;
text-transform: none;
white-space: break-spaces;
}
}
}
}
.img-scroll-view {
display: flex;
flex-wrap: nowrap;
white-space: nowrap;
box-sizing: border-box;
width: 750rpx;
.scroll-view-container {
// padding-left: 64rpx;
display: inline-block;
.scroll-view-item {
display: inline-block;
min-height: 154rpx;
background: #ffffff;
text-align: center;
.nav-item {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.text-title {
width: 112rpx;
font-weight: 400;
font-size: 28rpx;
color: #333333;
line-height: 28rpx;
white-space: break-spaces;
margin-top: 24rpx;
}
.image-container {
display: flex;
justify-content: center;
align-items: center;
.image {
background: #f3f3f3;
border-radius: 0px 0px 0px 0px;
}
}
}
}
}
}
}
// 两种方案 绝对定位 \ 使用translateX
.custom-scroll-container {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
padding-top: 24rpx;
.custom-scroll {
width: 60rpx;
overflow: hidden;
height: 6rpx;
background: #f3f3f3;
border-radius: 4px 4px 4px 4px;
position: relative;
.scroll {
width: 16rpx;
height: 6rpx;
background: #b2945e;
border-radius: 4px 4px 4px 4px;
/* 初始位置 */
transform: translateX(0rpx);
}
}
}
</style>