赞
踩
项目需求收集用户信息,其中包含用户的出生年月,如果让用户自己输入,体验不太友好,所以要求使用滑动选择的方式。
草稿效果图:
let yearList = [this.startYear - 2, this.startYear - 1];
for (let index = this.startYear; index <= this.endYear; index++) {
yearList.push(index);
}
yearList.push(this.endYear + 1, this.endYear + 2);
this.yearList = yearList;
这里,前后分别加了两个年份,以便拖动到最开始和最后的时候能选择。即:
<div class="year" v-for="(year, index) in yearList" :key="index">
{{ year }}
</div>
这里就得到了可以滑动的年份,但是没有选中的样式以及渐变的效果。
在设置了滑动的div中监听滑动:
<div class="year-box" @scroll.passive="scroll"></div>
passive使得滑动更平稳,监听函数:
scroll(e) {
// e.target.scrollHeight / this.yearListLength为每个选项高度
// e.target.scrollTop / (e.target.scrollHeight / this.yearListLength)判断滑动到哪一个选项
this.nowScrollYear = Math.round(
e.target.scrollTop / (e.target.scrollHeight / this.yearListLength)
);
this.year1 = this.nowScrollYear + this.startYear - 2;
this.year2 = this.nowScrollYear + this.startYear - 1;
this.year3 = this.nowScrollYear + this.startYear;
this.year4 = this.nowScrollYear + this.startYear + 1;
this.year5 = this.nowScrollYear + this.startYear + 2;
},
整体思路就是获取整个滑动盒子的高度,除以选项的个数,得到每一个选项的高度,再使用滑动盒子滑动的位置,判断滑动到哪一个选项,以此得到5个选项。
<div
class="year"
:class="[
year == year1 || year == year5 ? 'opcity3' : '',
year == year2 || year == year4 ? 'opcity6' : '',
year == year3 ? 'select' : '',
year == startYear - 1 || year == startYear - 2 || year == endYear + 1 || year == endYear + 2 ? 'opcity0' : '',
]"
v-for="(year, index) in yearList"
:key="index"
>
{{ year }}
</div>
year == startYear - 1 || year == startYear - 2 || year == endYear + 1 || year == endYear + 2 ? 'opcity0' : '' //判断是否为前后的两个选项
watch: {
show: {
handler: function (newVal) {
if(!newVal) return;
// 因为使用了v-if,所以需要等dom更新后才能获取
this.$nextTick(()=>{
let yearBox = document.getElementsByClassName("year-box")[0];
// 需要移动的选项个数
let needMoveNumber = this.nowYear - this.startYear;
yearBox.scrollTop = (yearBox.scrollHeight / this.yearListLength) * needMoveNumber;
})
},
deep: true,
}
},
主页面(引入后使用):
<date-picker
:show="showDatePicker"
:nowYear="nowYear"
@confirm="inputYear"
@hide="hideDataPicker"
></date-picker>
组件:
- <template>
- <div class="date-popup-box" v-if="show">
- <div class="mask" @click="hide"></div>
- <div class="date-box">
- <div class="year-box" @scroll.passive="scroll">
- <div
- class="year"
- :class="[
- year == year1 || year == year5 ? 'opcity3' : '',
- year == year2 || year == year4 ? 'opcity6' : '',
- year == year3 ? 'select' : '',
- year == startYear - 1 ||
- year == startYear - 2 ||
- year == endYear + 1 ||
- year == endYear + 2
- ? 'opcity0'
- : '',
- ]"
- v-for="(year, index) in yearList"
- :key="index"
- >
- {{ year }}
- </div>
- </div>
- <div class="btn-box">
- <div class="btn cancel" @click="hide"><span>Cancel</span></div>
- <div class="btn ok" @click="confirm"><span>OK</span></div>
- </div>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- name: "datePicker",
- props: {
- show: {
- type: Boolean,
- required: true,
- default: false,
- },
- nowYear: {
- type: Number,
- default: 1900,
- },
- startYear: {
- type: Number,
- default: 1900,
- },
- endYear: {
- type: Number,
- default: 2021,
- },
- },
- data() {
- return {
- yearList: [],
- year1: 1900,
- year2: 1901,
- year3: 1902,
- year4: 1903,
- year5: 1904,
- };
- },
- watch: {
- show: {
- handler: function (newVal) {
- if (!newVal) return;
- this.$nextTick(() => {
- let yearBox = document.getElementsByClassName("year-box")[0];
- // 需要移动的选项个数
- let needMoveNumber = this.nowYear - this.startYear;
- yearBox.scrollTop =
- (yearBox.scrollHeight / this.yearListLength) * needMoveNumber;
- });
- },
- deep: true,
- },
- },
- mounted() {
- let yearList = [this.startYear - 2, this.startYear - 1];
- for (let index = this.startYear; index <= this.endYear; index++) {
- yearList.push(index);
- }
- yearList.push(this.endYear + 1, this.endYear + 2);
- this.yearList = yearList;
- this.yearListLength = yearList.length;
- this.year1 = this.nowYear - 2;
- this.year2 = this.nowYear - 1;
- this.year3 = this.nowYear;
- this.year4 = this.nowYear + 1;
- this.year5 = this.nowYear + 2;
- },
- methods: {
- confirm() {
- this.$emit("confirm", this.year3);
- },
- hide() {
- this.$emit("hide");
- },
- scroll(e) {
- // e.target.scrollHeight / this.yearListLength为每个选项高度
- // e.target.scrollTop / (e.target.scrollHeight / this.yearListLength)判断滑动到哪一个选项
- this.nowScrollYear = Math.round(
- e.target.scrollTop / (e.target.scrollHeight / this.yearListLength)
- );
- this.year1 = this.nowScrollYear + this.startYear - 2;
- this.year2 = this.nowScrollYear + this.startYear - 1;
- this.year3 = this.nowScrollYear + this.startYear;
- this.year4 = this.nowScrollYear + this.startYear + 1;
- this.year5 = this.nowScrollYear + this.startYear + 2;
- },
- },
- };
- </script>
-
- <style scoped>
- .date-popup-box {
- position: absolute;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100%;
- }
- .date-popup-box .mask {
- width: 100vw;
- height: 100%;
- position: absolute;
- top: 0;
- left: 0;
- }
- @keyframes datePopup {
- from {
- transform: translateY(100%);
- opacity: 0;
- }
- to {
- transform: translateY(0);
- opacity: 1;
- }
- }
- .date-box {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100vw;
- height: 40%;
- color: #ffffff;
- background-color: #2c2c2c;
- border-radius: 6vw 6vw 0 0;
- padding: 10% 0;
- box-sizing: border-box;
- animation: datePopup 0.3s;
- animation-timing-function: ease-out;
- }
- .date-box .year-box {
- height: 80%;
- overflow-y: scroll;
- }
- .date-box .year-box .year {
- padding: 3vw;
- opacity: 0.1;
- transition: 0.1s;
- font-size: 4vw;
- }
- .date-box .year-box .year.opcity3 {
- opacity: 0.4;
- }
- .date-box .year-box .year.opcity6 {
- opacity: 0.7;
- }
- .date-box .year-box .year.select {
- font-size: 5vw;
- opacity: 1;
- }
- .date-box .year-box .year.opcity0 {
- opacity: 0;
- }
- .date-box .btn-box {
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 50vw;
- margin-left: 25vw;
- margin-top: 8vw;
- }
- .date-box .btn-box .btn {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 20vw;
- height: 8vw;
- border: 0.53vw solid;
- border-radius: 2vw;
- }
- .date-box .btn-box .btn.cnacel {
- color: #ffffff;
- background-color: gainsboro;
- }
- .date-box .btn-box .btn.ok {
- color: #000;
- background-color: #fff;
- }
- </style>
实现的代码比较粗糙,如有问题,欢迎交流。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。