scrollList组件 - vue3
子组件
<template>
<view>
<scroll-view scroll-x="true" @scroll="scrollChange" id='scrollBox'>
<view id='scrollContain' class="contain" :style="scrollContain">
<view class="item" :style="itemStyle" v-for="item in datas.titleList" @click="clickItem(item.name)">
<view class="icon">
<image class="image" :src="item.iconPath" mode="aspectFill"></image>
</view>
<view class="title" :style="{'fontSize':size}">
{{item.name}}
</view>
</view>
</view>
</scroll-view>
<view v-if="showScrollBar" class="scrollBar" :style="scrollBarStyle">
<view :style="scrollSliderStyle" class="innerBar"></view>
</view>
</view>
</template>
<script setup>
import {
onMounted,
reactive,
ref
} from 'vue';
let datas = defineProps(['titleList', 'scrollBarWrapStyle', 'scrollContainStyle', 'scrollBarStyle', 'count','size','row' ])
// 显示区域宽
let scrollBoxWidth = ref(0)
// 滚动容器部分 - 包含隐藏部分
let scrollContain = ref({})
let left = ref(0)
// 滚动条容器
let scrollBarStyle = ref({
backgroundColor: '#f0f'
})
// 滚动条
let scrollSliderStyle = ref({
backgroundColor: '#00f',
marginLeft: '0'
})
// 每一个item块
let itemStyle = ref({
width: '0px'
})
// 是否显示滚动条
let showScrollBar = ref(true)
onMounted(() => {
initScroll()
initStyle()
});
// 初始化滚动列表 - 宽,高,显示/隐藏部分
const initScroll = () => {
// console.log(datas.titleList.length);
const query = uni.createSelectorQuery().in();
query.select('#scrollBox').boundingClientRect(res => {
scrollBoxWidth.value = res.width; // 显示区域宽
let {row} = datas
itemStyle.value = {
...itemStyle.value,
width: res.width / datas.count + 'px'
}
console.log(itemStyle.value);
if(!row || row == 1){
// 单行
scrollContain.value = { //容器总宽
...scrollContain.value,
width: parseFloat(itemStyle.value.width) * datas.titleList.length + 'px'
}
}else{
// 多行
let itemList = datas.titleList.length
if(datas.titleList.length%2!=0){itemList = datas.titleList.length + 1}
let col = Math.ceil(itemList / row)
scrollContain.value = {
...scrollContain.value,
width: parseFloat(itemStyle.value.width) * col + 'px'
}
}
console.log(scrollContain.value);
// 当总宽度等于显示宽度时隐藏滚动条
if (parseFloat(scrollContain.value.width) <= res.width) {
showScrollBar.value = false
}
}).exec();
}
// 初始化滚动条
const initStyle = () => {
if (datas.scrollBarWrapStyle) {
changeScrollBarWrapStyle();
}
if (datas.scrollBarStyle) {
changeScrollBarStyle();
}
if (datas.scrollContainStyle) {
changeScrollContain();
}
}
// 修改内部容器样式
const changeScrollContain = () => {
scrollContain.value = {
...scrollContain.value,
backgroundColor: datas.scrollContainStyle.backgroundColor
};
}
// 修改滚动条容器样式
const changeScrollBarWrapStyle = () => {
// console.log(datas.scrollBarWrapStyle.backgroundColor);
scrollBarStyle.value = datas.scrollBarWrapStyle;
};
// 修改滚动条样式
const changeScrollBarStyle = () => {
scrollSliderStyle.value = {
...scrollSliderStyle.value,
backgroundColor: datas.scrollBarStyle.backgroundColor
};
};
// 设置滚动距离
const scrollChange = (e) => {
let value = parseFloat(scrollContain.value.width) - scrollBoxWidth.value;
let newValue = e.detail.scrollLeft / value;
scrollSliderStyle.value = {
...scrollSliderStyle.value,
marginLeft: newValue * 60 + 'rpx'
};
};
const clickItem = (name) => {
console.log(name);
};
</script>
<style scoped>
.scrollBar {
position: relative;
top: -20rpx;
width: 100rpx;
height: 10rpx;
margin: auto;
border-radius: 20px;
}
.innerBar {
width: 40rpx;
height: 10rpx;
border-radius: 20px;
}
.contain {
display: flex;
flex-wrap: wrap;
}
.item {
box-sizing: border-box;
padding: 10rpx;
height: 200rpx;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.image {
width: 100rpx;
height: 100rpx;
border-radius: 20rpx;
}
</style>
父组件
<script setup>
import {
onMounted,
reactive,
ref
} from 'vue';
import scrollList from '../../components/scrollList/scrollList.vue'
// 数据源
const lists = ref([{
iconPath: '../../static/logo.png',
name: '张三'
},
{
iconPath: '../../static/logo.png',
name: '李四'
},
{
iconPath: '../../static/logo.png',
name: '李四'
},
{
iconPath: '../../static/logo.png',
name: '王五'
},
{
iconPath: '../../static/logo.png',
name: '赵六'
},
{
iconPath: '../../static/logo.png',
name: '赵六'
},
{
iconPath: '../../static/logo.png',
name: '赵六'
},
{
iconPath: '../../static/logo.png',
name: '赵六'
},
])
// 下方滚动容器样式
const scrollBarWrapStyle = ref({
backgroundColor: '#f00'
})
// 下方滚动条样式
const scrollBarStyle = ref({
backgroundColor: '#000'
})
// 内容区域样式
const scrollContainStyle = ref({
backgroundColor: '#fff'
})
// 文字大小 - 支持px/rpx/em
const size = ref('20rpx')
// 显示数量
const count = ref(3)
// 行数
let row = ref(2);
onMounted(() => {
});
</script>
<template>
<view>
<scrollList :titleList="lists" :scrollBarWrapStyle="scrollBarWrapStyle" :scrollBarStyle="scrollBarStyle"
:count="count" :scrollContainStyle="scrollContainStyle" :size="size" :row="row">
</scrollList>
</view>
</template>
<style scoped>
.grid-text {
font-size: 14px;
color: #909399;
}
</style>