背景
新项目为了省事和后台写一起了,所以用不了Uni-app(悲),然后element-ui的日期选择器h5不适配,看着也难受,就想找个好用的,结果找了一圈感慨,自己写个吧。
说明
为了加快速度,代码可能有些臃肿,但大概就是这样了,看着代码好多,其实只要会一个的滚动就会多个了。建议下看下参考文章,然后研究下单个滚动选择器是怎么实现的。
参考文章
(66条消息) vue滚动选择器效果的实现(文字动态效果)_vue实现滚动效果_是浅笑耶的博客-CSDN博客
代码
<template> <div class="picker"> <div class="box-picker"> <div class="solidUl" @scroll="scrollChange"> <ul> <li id="year" v-for="(item, index) in yearList" :key="index">{{ item }}年</li> </ul> </div> </div> <div class="box-picker"> <div class="solidUl" @scroll="scrollChange1"> <ul> <li id="mound" v-for="(item, index) in moundList" :key="index">{{ item }}月</li> </ul> </div> </div> <div class="box-picker"> <div class="solidUl" @scroll="scrollChange2"> <ul> <li id="day" v-for="(item, index) in dayList" :key="index">{{ item }}日</li> </ul> </div> </div> <div class="topButton"> <div> </div> <div>请选择</div> <div @click="handleClose">完成</div> </div> <!-- 滚动过程中滚动到的所需位置 --> <div class="backgroundFloat"></div> </div> </template> <script> export default { name: 'datePicker', data() { return { yearList: [], moundList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], dayList: [], bigMound: [1, 3, 5, 7, 8, 10, 12], smallMound: [4, 6, 9, 11], day: 14, year: 2023, mound: 7, height: 160, distance: 30, } }, watch: { year() { if (this.mound == 2) { this.dayList = [] if ((this.year % 4 == 0 && this.year % 100 != 0) || (this.year % 400 == 0)) { for (let j = 1; j <= 29; j++) { this.dayList.push(j) } } else { for (let j = 1; j <= 28; j++) { this.dayList.push(j) } } } }, mound() { this.dayList = [] if (this.mound == 2) { if ((this.year % 4 == 0 && this.year % 100 != 0) || (this.year % 400 == 0)) { for (let j = 1; j <= 29; j++) { this.dayList.push(j) } } else { for (let j = 1; j <= 28; j++) { this.dayList.push(j) } } } else { let arr = this.bigMound.filter(e => { return e == this.mound }) if (arr.length > 0) { for (let j = 1; j <= 31; j++) { this.dayList.push(j) } } else { for (let j = 1; j <= 30; j++) { this.dayList.push(j) } } } } }, mounted() { for (let i = 2024; i <= 2100; i++) { this.yearList.push(i) } for (let j = 1; j <= 31; j++) { this.dayList.push(j) } var scrollList = document.querySelectorAll('.solidUl') // 触发监听 this.$nextTick(() => { scrollList.forEach(e => { e.scrollTop = e.scrollTop + 1 }) }) }, methods: { scrollChange(e) { //首先获取到li元素 var year = document.querySelectorAll('#year') //对li元素进行遍历 for (var i = 0; i < year.length; i++) { //offsetTop返回当前元素相对于节点顶部偏移量,scrollTop返回一个元素垂直滚动的距离 //在滚动过程中,lis[i].offsetTop-e.target.scrollTop可获取到当前元素距离顶部的位置 //打印出结果自己对比,选择自己需要范围的值,我给li设置的高度为40px,因此185与225之间相差${distance}, //而${height}与150+${distance}是我实际输出对比测量的我需要元素滚动到该位置时设置样式。 if ((year[i].offsetTop - e.target.scrollTop) > this.height && (year[i].offsetTop - e.target.scrollTop) < this.height + this.distance) { //当元素滚动到当前位置时,先将元素原来为"active2"的class属性去掉 //再给元素增加"active"的属性 // console.log(year[i].textContent); this.year = year[i].textContent.slice(0, 4) year[i].classList.remove("active2") year[i].classList.add("active") //给当前元素以上的元素动态设置文字大小,离当前文字越远,文字大小越小 for (var j = 1; j <= i; j++) { year[i - j].style.fontSize = (20 - 2 * j) + 'px' } //给当前元素以下的元素动态设置文字大小,离当前文字越远,文字大小越小 for (var a = 1; a < year.length - i; a++) { year[i + a].style.fontSize = (20 - 2 * a) + 'px' } //当没滚动到期待位置时,也就是其他所有元素,移除"active"的样式,增加"active2"的样式 } else { year[i].classList.remove("active") year[i].classList.add("active2") } } }, scrollChange1(e) { //首先获取到li元素 var mound = document.querySelectorAll('#mound') //对li元素进行遍历 for (var i = 0; i < mound.length; i++) { //offsetTop返回当前元素相对于节点顶部偏移量,scrollTop返回一个元素垂直滚动的距离 //在滚动过程中,lis[i].offsetTop-e.target.scrollTop可获取到当前元素距离顶部的位置 //打印出结果自己对比,选择自己需要范围的值,我给li设置的高度为40px,因此185与225之间相差${distance}, //而${height}与150+${distance}是我实际输出对比测量的我需要元素滚动到该位置时设置样式。 if ((mound[i].offsetTop - e.target.scrollTop) > this.height && (mound[i].offsetTop - e.target.scrollTop) < this.height + this.distance) { //当元素滚动到当前位置时,先将元素原来为"active2"的class属性去掉 //再给元素增加"active"的属性 this.mound = mound[i].textContent.slice(0, -1) mound[i].classList.remove("active2") mound[i].classList.add("active") //给当前元素以上的元素动态设置文字大小,离当前文字越远,文字大小越小 for (var j = 1; j <= i; j++) { mound[i - j].style.fontSize = (20 - 2 * j) + 'px' } //给当前元素以下的元素动态设置文字大小,离当前文字越远,文字大小越小 for (var a = 1; a < mound.length - i; a++) { mound[i + a].style.fontSize = (20 - 2 * a) + 'px' } //当没滚动到期待位置时,也就是其他所有元素,移除"active"的样式,增加"active2"的样式 } else { mound[i].classList.remove("active") mound[i].classList.add("active2") } } }, scrollChange2(e) { //首先获取到li元素 var day = document.querySelectorAll('#day') //对li元素进行遍历 for (var i = 0; i < day.length; i++) { //offsetTop返回当前元素相对于节点顶部偏移量,scrollTop返回一个元素垂直滚动的距离 //在滚动过程中,lis[i].offsetTop-e.target.scrollTop可获取到当前元素距离顶部的位置 //打印出结果自己对比,选择自己需要范围的值,我给li设置的高度为40px,因此185与225之间相差${distance}, //而${height}与150+${distance}是我实际输出对比测量的我需要元素滚动到该位置时设置样式。 if ((day[i].offsetTop - e.target.scrollTop) > this.height && (day[i].offsetTop - e.target.scrollTop) < this.height + this.distance) { //当元素滚动到当前位置时,先将元素原来为"active2"的class属性去掉 //再给元素增加"active"的属性 this.day = day[i].textContent.slice(0, -1) day[i].classList.remove("active2") day[i].classList.add("active") //给当前元素以上的元素动态设置文字大小,离当前文字越远,文字大小越小 for (var j = 1; j <= i; j++) { day[i - j].style.fontSize = (20 - 2 * j) + 'px' } //给当前元素以下的元素动态设置文字大小,离当前文字越远,文字大小越小 for (var a = 1; a < mound.length - i; a++) { day[i + a].style.fontSize = (20 - 2 * a) + 'px' } //当没滚动到期待位置时,也就是其他所有元素,移除"active"的样式,增加"active2"的样式 } else { day[i].classList.remove("active") day[i].classList.add("active2") } } }, handleClose(){ console.log(121); this.$emit('handleClose') } }, } </script> <style lang="scss" scoped> .picker { display: flex; // border: 1px solid hsl(0, 0%, 60%); align-items: center; box-sizing: border-box; // height: 200px; overflow: hidden; position: relative; } .topButton { width: 100%; padding-bottom: 10px; padding-top: 3px; position: absolute; top: 0; display: flex; background: rgb(247, 247, 248); } .topButton>div { flex: 1; } .topButton>div:nth-child(2n) { text-align: center; } .topButton>div:nth-child(2n-1) { text-align: right; padding-right: 10px; color: #45db2b; } .solidUl::-webkit-scrollbar { display: none } .box-picker { height: 300px; width: 300px; } .solidUl { height: 100%; //滚动设置在div内 overflow-y: scroll; //增加滚动的流畅性 touch-action: pan-y; -webkit-overflow-scrolling: touch; } ul { padding: 170px 0 100px 0; margin: 0; background-color: #fff; li { list-style: none; font-size: 18px; line-height: 30px; text-align: center; opacity: 0.3; height: 30px; background-color: #fff; } } .active { font-weight: 400; font-size: 20px !important; color: #333; //不透明度需要高点,因为有backgroundFloat颜色的影响 opacity: 1.2 !important; top: 150px; } .active2 { color: #333; //设置不透明度 opacity: 0.6 !important; } //给滚动到的所需位置增加背景色等样式 .backgroundFloat { width: 100%; height: 30px; background-color: #d1d1d1; //降低不透明度,以防遮挡文字 opacity: 0.2; position: absolute; top: 170px; border: 1px solid #999; } </style>
标签:vue,滚动,元素,height,year,scrollTop,mound,h5,选择器 From: https://www.cnblogs.com/piaohd/p/17563575.html