uniapp 实现自定义缩略滚动条效果
作者:清云随笔
这篇文章主要介绍了uniapp 实现自定义缩略滚动条,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

<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>补充:Vue3 通过 axios 获取项目本地图片文件进行上传
<template>
<input
type="file"
ref="imageInput"
style="display: none"
@change="uploadImage"
/>
</template>
<script lang="tsx" setup>
import axios from 'axios'
import { ref, defineExpose, reactive } from 'vue'
import { ElMessage } from 'element-plus'
const imageInput = ref<any>(null)
// 1、项目本地实现上传 方法
async function localUplaod() {
const imageUrl = require('@/assets/wxapp-icon/test.png') // 本地项目的路径
const file = await getLocalImageAsFile(imageUrl)
const response = await uploadAPI(file)
}
// 2、模拟点击事件,实现 本地电脑选择让图片上传
function handleClick(e) {
imageInput.value && imageInput.value.click()
}
// 自定义图片上传
async function uploadImage(event) {
const files = event.target.files
if (files.length === 0) {
ElMessage.error('没有选择文件')
return
}
// 读取第一个文件(假设用户只选择一个文件)
const file = files[0]
if (!file.type.match('image/*')) {
ElMessage.error('请选择一个图片文件')
return
}
// 调用上传API函数
try {
const response = await uploadAPI(file)
console.log('上传成功', response)
ElMessage.success('上传成功')
close()
} catch (error) {
console.log('error', error)
ElMessage.error('上传失败')
}
}
// 获取本地图片
async function getLocalImageAsFile(imagePath) {
try {
const response = await axios.get(imagePath, {
responseType: 'blob' // 指定响应类型为blob
})
if (response.status === 200) {
// 使用 Blob 创建 File 对象
const file = new File([response.data], 'image.png', { type: 'image/png' })
return file
}
} catch (error) {
console.error('获取图片文件失败:', error)
throw error
}
}
// 上传API
function uploadAPI(dataFile) {
const file = dataFile
// 组装成文件格式进行上传
const formDatas = new FormData()
formDatas.append('file', file)
return new Promise((resolve, reject) => {
axios
.post<any, any>({
url: `xxx/xxx/xxx/xxx/xxx/xxx 上传地址`,
data: formDatas,
headers: { 'Content-Type': 'multipart/form-data' }
})
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err)
})
})
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped></style>到此这篇关于uniapp 实现自定义缩略滚动条的文章就介绍到这了,更多相关uniapp滚动条内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
