最近得到一个需求,要实现一个如下图所示的日期滚动选择器,在网上找了许久都没找到合适的,无奈只能自己写一个。
先实现单个滚动选择效果,scrollbarPicker.vue文件代码如下:
<template>
<div>
<el-scrollbar
ref="scrollMenuRef"
class="scrbar scrollbar"
>
<div @mouseleave="handleMouseLeave">
<div
class="scrbalScrollBox"
v-for="(item, index) in list"
:key="'li' + index"
@click="scrollTo(item)"
:class="{ active_li: item == activeItem }"
>
{{ item }}
</div>
</div>
</el-scrollbar>
</div>
</template>
<script>
export default {
props: {
value: String,
data: {
type: Number,
default: 40,
},
type: {
type: String,
default: 'year',
},
},
data() {
return {
itemHeight: 40,
activeItem: '1950',
scrollTopNum: 0,
list: [],
};
},
mounted() {
this.getDataList();
},
methods: {
getDataList() {
switch (this.type) {
case 'year':
this.list = this.getYearArr();
break;
case 'month':
this.list = this.generateNumberArray(11);
break;
case 'day':
this.list = this.generateNumberArray(30);
break;
default:
break;
}
this.activeItem = this.value;
this.$nextTick(() => {
this.scrollTo(this.value);
});
this.$refs.scrollMenuRef.wrap.addEventListener('scroll', this.scrollMenu);
},
generateNumberArray(n) {
let arr = Array.from({ length: n + 1 }, (_, i) => String(i + 1).padStart(2, '0'));
arr = ['', '', ...arr, '', ''];
return arr;
},
getYearArr() {
let start = 1950;
let end = 2024;
let arr = [];
for (let i = start; i <= end; i++) {
arr.push(`${i}`);
}
arr = ['', '', ...arr, '', ''];
return arr;
},
handleMouseLeave() {
if (this.scrollTopNum % 40 != 0) {
this.$refs.scrollMenuRef.wrap.scrollTop = this.toggleNum(this.scrollTopNum);
}
},
updateValue(value) {
this.$emit('input', value);
},
scrollTo(titleNo) {
let index = this.list.indexOf(titleNo);
index -= 2;
let num = index * this.itemHeight;
this.$refs.scrollMenuRef.wrap.scrollTop = num;
},
toggleNum(num) {
if (num % this.itemHeight == 0) {
return num;
} else {
let num1 = num % this.itemHeight;
return this.itemHeight - num1 + num;
}
},
scrollMenu(e) {
this.scrollTopNum = e.target.scrollTop;
let val = Math.round(this.scrollTopNum / this.itemHeight);
this.activeItem = `${this.list[val + 2]}`;
this.updateValue(this.activeItem);
},
},
};
</script>
<style scoped>
.scrollbar ::v-deep .el-scrollbar__wrap {
overflow-x: hidden;
}
.scrbalScrollBox {
height: 40px;
box-sizing: border-box;
line-height: 40px;
color: #bfc2c9;
/* background: rgba(216, 216, 216, 0.4); */
}
.active_li {
color: #000;
border-top: 1px solid #bfc2c9;
border-bottom: 1px solid #bfc2c9;
}
.scrollbar {
height: 200px;
width: 80px;
border-radius: 10px;
font-size: 18px;
text-align: center;
}
.is-horizontal {
display: block;
}
/* 不展示水平滚动条 */
::v-deep .is-horizontal {
display: none;
}
</style>
再将其组合起来 index.vue文件代码如下:
<template>
<div>
<div
class="content_date"
@click="handleClick"
>
<span>请选择</span>
<div
class="dateView"
v-if="divalog"
>
<div class="dateView-content">
<div>
<div class="date_box">
<div class="box_item">
<p>年</p>
<scrollPicker
v-model="dateData.startYear"
:type="'year'"
></scrollPicker>
</div>
<div class="box_item">
<p>月</p>
<scrollPicker
v-model="dateData.startMonth"
:type="'month'"
:data="12"
></scrollPicker>
</div>
<div class="box_item">
<p>日</p>
<scrollPicker
v-model="dateData.startDay"
:type="'day'"
:data="31"
></scrollPicker>
</div>
</div>
</div>
</div>
<div class="divider"></div>
<div class="dateView_footer">
<el-button
size="small"
@click.stop="handleClose"
>取消</el-button
>
<el-button
size="small"
type="primary"
@click.stop="handleConfirm"
>确认</el-button
>
</div>
<div class="box_arrow"></div>
</div>
<div
ref="word"
class="print-main"
></div>
</div>
</div>
</template>
<script>
import scrollPicker from './scrollbarPicker.vue';
export default {
components: {
scrollPicker,
},
data() {
return {
divalog: false,
dateData: {
startYear: '1950',
startMonth: '01',
startDay: '03',
},
};
},
mounted() {
this.handleScrll();
},
methods: {
handleScrll() {
// this.$refs.testScroll.wrap.scrollTop += 100;
// console.log(this.$refs.testScroll.wrap.scrollTop);
},
handleClick() {
this.divalog = true;
},
handleClose() {
this.divalog = false;
},
handleConfirm() {
console.log(this.dateData);
let date = this.dateData.startYear + '-' + this.dateData.startMonth + '-' + this.dateData.startDay;
console.log(date);
this.divalog = false;
},
},
};
</script>
<style lang="scss">
.scrollMenuBox {
height: 200px;
}
.scroll_box {
width: 200px;
background-color: white;
.testBox {
height: 50px;
width: 80px;
line-height: 50px;
text-align: center;
border-bottom: 1px solid #000;
}
}
.print-main {
position: fixed;
top: -10000px; //不在页面上显示
/deep/.docx-wrapper {
background: none;
}
/deep/.docx-wrapper > section.docx {
margin-bottom: 0;
}
}
.content_date {
width: 180px;
height: 40px;
font-size: 14px;
margin: 50px;
display: inline-block;
position: relative;
border: 1px solid #dcdfe6;
box-sizing: border-box;
background-color: #fff;
line-height: 40px;
color: #606266;
border-radius: 4px;
cursor: pointer;
padding: 0 15px;
}
.dateView {
background-color: #fff;
position: absolute;
left: 0;
top: 46px;
// width: 300px;
.dateView-content {
padding: 10px 20px 0;
display: flex;
}
.date_box {
display: flex;
justify-content: space-between;
position: relative;
}
p {
font-size: 18px;
font-weight: 700;
text-align: center;
margin: 0;
}
}
.box_item {
width: 80px;
text-align: center;
}
.divider {
width: 100%;
height: 1px;
margin: 4px 0;
background-color: #dcdfe6;
}
.dateView_footer {
text-align: right;
padding: 0 10px 4px;
}
.box_arrow {
width: 0;
height: 0;
border: 10px solid transparent;
border-bottom-color: #fff;
position: absolute;
top: -18px;
left: 30px;
}
</style>