uni-app自定义日期选择器和时间选择器,解决IOS端和安卓端显示不同问题
描述:
原本用的原生组件picker,设置了开始时间和结束时间,安卓端可以显示可选日期时间部分,但是IOS显示的内容包括一整天时间和N个年,本来只需要选择其中七天,那么其他天不显示,IOS端可以滑到其他日期位置,但是会自己滚回来
IOS端:
安卓:
这里只需要八点后和19点前(8:00-19:00)的时间
因此改成自定义自写的组件
代码:
日期选择:
<template>
<view>
<view v-show="propDate">
<view class="win-container">
<view class="win-mask" />
<view class="win-content">
<uni-popup ref="popup" type="bottom">
<view class="operation-title">
<view class="cancel" @click="cancel">取消</view>
<view class="title">选择日期</view>
<view class="confirm" @click="okBtnTime">确定</view>
</view>
<picker-view
indicator-style="height: 50px;"
style="width: 100%; height: 300px;"
:value="value"
@change="bindChange"
>
<picker-view-column>
<view v-for="(item, index) in years" :key="index" style="line-height: 50px; text-align: center;">{{ item }}年</view>
</picker-view-column>
<picker-view-column>
<view v-for="(item, index) in months" :key="index" style="line-height: 50px; text-align: center;">{{ item }}月
</view>
</picker-view-column>
<picker-view-column>
<view v-for="(item, index) in days" :key="index" style="line-height: 50px; text-align: center;">{{ item }}日</view>
</picker-view-column>
</picker-view>
</uni-popup>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
visible: {
type: Boolean,
default: false
},
firstDay: {
type: [String, Number],
default: 0
}
},
data() {
// const date = new Date() // 获取系统日期
const years = []
const months = []
const days = []
console.log('年月日转换为时间戳:[当前日期][七天后]', this.fun_date(this.firstDay), this.fun_date(this.firstDay + 6))
const startDate = this.fun_date(this.firstDay).split('-').map(Number)
const endDate = this.fun_date(this.firstDay + 6).split('-').map(Number)
const getYear = startDate[0]
const getMonth = startDate[1]
const getDate = startDate[2]
// 年
console.log('获取年份', startDate[0], endDate[0])
if (startDate[0] !== endDate[0]) {
for (let i = startDate[0]; i <= endDate[0]; i++) {
years.push(i)
}
} else {
years.push(startDate[0])
}
// 月
console.log('获取月份', startDate[1], endDate[1])
if (startDate[1] !== endDate[1]) {
for (let i = startDate[1]; i <= endDate[1]; i++) {
months.push(i)
}
} else {
months.push(startDate[1])
}
// 日
console.log('获取天', startDate[2], endDate[2])
if (startDate[2] < endDate[2]) {
for (let i = startDate[2]; i <= endDate[2]; i++) {
days.push(i)
}
} else {
for (let i = startDate[2]; i <= 31; i++) {
days.push(i)
}
}
return {
years: years,
year: getYear,
months: months,
month: getMonth,
days: days,
day: getDate,
value: [0, 0, 0],
isDaytime: true,
timeInput: '',
propDate: false,
returnDate: []
}
},
watch: {
visible: {
handler(val) {
this.propDate = val
this.dateMainBtn()
}
}
},
mounted() {
console.log('日期弹窗show')
this.dateMainBtn()
},
methods: {
fun_date(aa) {
const date1 = new Date()
// const time1 = date1.getFullYear() + '-' + (date1.getMonth() + 1) + '-' + date1.getDate() // time1表示当前时间
var date2 = new Date(date1)
date2.setDate(date1.getDate() + aa)
const time2 = date2.getFullYear() + '-' + (date2.getMonth() + 1) + '-' + date2.getDate()
return time2
},
// 将日期分开写入对应数组
dateMainBtn() {
const setYear = this.year
const setMonth = this.month
const setDay = this.day
const dateTimeBody = setYear + '-' + setMonth + '-' + setDay
this.returnDate = [setYear, setMonth, setDay]
console.log('日期弹窗默认数据', dateTimeBody)
},
okBtnTime() {
console.log('日期数组', this.returnDate)
this.$emit('change', this.returnDate)
this.$emit('update:visible', false)
this.timeInput = wx.getStorageSync('adminDate') + wx.getStorageSync('adminTodays')
},
cancel() {
this.$emit('update:visible', false)
},
// 判断元素是否在一个数组
contains(arr, obj) {
var i = arr.length
while (i--) {
if (arr[i] === obj) {
return true
}
}
return false
},
setDays(satrtDay, endDay) {
const temp = []
for (let i = satrtDay; i <= endDay; i++) {
temp.push(i)
}
this.days = temp
},
// 选择滚动器改变触发事件
bindChange(e) {
const bigMonth = [1, 3, 5, 7, 8, 10, 12]
const val = e.detail.value
// 判断月的天数
const setYear = this.years[val[0]]
const setMonth = this.months[val[1]]
const startDate = this.fun_date(this.firstDay).split('-').map(Number)
const endDate = this.fun_date(this.firstDay + 6).split('-').map(Number)
// 闰年
if (startDate[1] !== endDate[1]) { // (不在同一个月)
console.log('横跨两个月')
if (startDate[1] === setMonth) { // 如果开始月份等于选择的月份
console.log('开始月份等于选择的月份', startDate[1], setMonth)
if (setMonth === 2) { // 2月特殊处理
if (setYear % 4 === 0 && setYear % 100 !== 0) {
console.log('闰年')
this.setDays(startDate[2], 29)
} else {
console.log('非闰年')
this.setDays(startDate[2], 28)
}
} else { // 非2月
// 大月
if (this.contains(bigMonth, setMonth)) {
this.setDays(startDate[2], 31)
} else {
this.setDays(startDate[2], 30)
}
}
} else if (endDate[1] === setMonth) { // 如果结束月份等于选择的月份
console.log('结束月份等于选择的月份', endDate[2])
this.setDays(1, endDate[2])
}
} else { // 在同一个月
this.setDays(startDate[2], endDate[2])
}
const setDay = this.days[val[2]]
this.year = setYear
this.month = setMonth
this.day = setDay
this.isDaytime = !val[3]
const dateTimeBody = setYear + '-' + setMonth + '-' + setDay
console.log('滑动后的日期', dateTimeBody)
this.returnDate = [setYear, setMonth, setDay]
wx.setStorageSync('adminDate', dateTimeBody)
}
}
}
</script>
<style lang="scss" scoped>
.center {
display: flex;
justify-content: center;
align-items: center;
}
.win-container {
bottom: 0;
width: 100%;
font-size: 32rpx;
@extend .center;
position: fixed;
z-index: 20;
left: 0;
.win-mask {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
z-index: 20;
position: fixed;
top: 0;
left: 0;
bottom: 0;
}
.win-content {
width: 100%;
max-height: 60vh;
position: absolute;
// overflow: auto;
bottom: 0;
left: 0;
// @extend .center;
background-color: #FFFFFF;
z-index: 21;
border-radius: 32rpx 32rpx 0 0;
.operation-title {
@extend .center;
height: 136rpx;
font-size: 32rpx;
font-weight: bold;
align-items: center;
view {
flex: 1;
text-align: center;
}
.title {
font-size: 36rpx;
}
.cancel {
color: #666666;
}
.confirm {
color: #2E4CFF;
}
}
}
}
</style>
时间选择
<template>
<view>
<view v-show="show">
<view class="win-container">
<view class="win-mask" />
<view class="win-content">
<uni-popup ref="popup" type="bottom">
<view class="operation-title">
<view class="cancel" @click="cancel">取消</view>
<view class="title">选择日期</view>
<view class="confirm" @click="confirm">确定</view>
</view>
<picker-view
class="picker-view"
:indicator-style="indicatorStyle"
:value="value"
@change="bindChange"
>
<picker-view-column>
<view v-for="(item,index) in hours" :key="index" class="item">{{ item }}时</view>
</picker-view-column>
<picker-view-column>
<view v-for="(item,index) in minutes" :key="index" class="item">{{ item }}分</view>
</picker-view-column>
</picker-view>
</uni-popup>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
visible: {
type: Boolean,
default: false
},
isThisToday: {
type: Boolean,
default: false
}
},
data() {
const date = new Date()
const hours = []
const hour = date.getHours() + 1
const minutes = []
const minute = date.getMinutes()
console.log('hour', hour)
for (let i = 8; i <= 19; i++) {
if (i < 10) {
hours.push('0' + i)
} else {
hours.push(i)
}
}
for (let i = 0; i <= 59; i++) {
if (i < 10) {
minutes.push('0' + i)
} else {
minutes.push(i)
}
}
return {
hours,
minutes,
hour,
minute,
value: [0, 0],
show: false,
indicatorStyle: `height: 50px;`,
maskStyle: 'padding:10px 0'
}
},
watch: {
visible: {
handler(val) {
this.show = val
}
},
isThisToday: {
handler(val) {
if (val) {
this.setHours(this.getNowTime()[0], 19)
this.setMinutes(this.getNowTime()[1], 59)
const setHour = this.hour
const setMinute = this.minute
this.value = [this.hours.map(Number).map(item => item).indexOf(setHour), this.minutes.map(Number).map(item => item).indexOf(setMinute)]
} else {
this.setHours(8, 19)
this.setMinutes(0, 59)
const setHour = this.hour
const setMinute = this.minute
this.value = [this.hours.map(Number).map(item => item).indexOf(setHour), this.minutes.map(Number).map(item => item).indexOf(setMinute)]
}
console.log('日期选择了当天', val)
}
}
},
mounted() {
this.timeMainBtn()
},
methods: {
timeMainBtn() {
const setHour = this.hour
const setMinute = this.minute
const dateTimeBody = setHour + '时' + setMinute + '分'
this.returnTime = setHour + ':' + setMinute
this.value = [this.hours.map(Number).map(item => item).indexOf(setHour), this.minutes.map(Number).map(item => item).indexOf(setMinute)]
console.log('时间弹窗默认数据', dateTimeBody, this.value)
},
bindChange(e) {
const val = e.detail.value
const setHour = this.hours[val[0]]
if (setHour === 19) {
this.minutes = ['00']
} else if ((parseInt(setHour) === this.getNowTime()[0]) && this.isThisToday) {
this.setMinutes(this.getNowTime()[1], 59)
} else {
this.setMinutes(0, 59)
}
const setMinute = this.minutes[val[1]]
this.value = val
console.log('this.value', this.value)
console.log('选择了时间', setHour + '时' + setMinute + '分', '现在的时间', ((parseInt(setHour) === this.getNowTime()[0] + 1) && this.isThisToday))
},
setHours(satrtHour, endHour) {
const res = []
for (let i = satrtHour; i <= endHour; i++) {
if (i < 10) {
res.push('0' + i)
} else {
res.push(i)
}
}
this.hours = res
},
setMinutes(satrtMinute, endMinute) {
const temp = []
for (let i = satrtMinute; i <= endMinute; i++) {
if (i < 10) {
temp.push('0' + i)
} else {
temp.push(i)
}
}
this.minutes = temp
},
cancel() {
this.$emit('update:visible', false)
},
confirm() {
this.returnTime = this.hours[this.value[0]] + ':' + this.minutes[this.value[1]]
console.log('现在选择的时间', this.returnTime)
this.$emit('change', this.returnTime)
this.$emit('update:visible', false)
},
// 获取当前时间
getNowTime() {
const date = new Date()
const hour = date.getHours() + 1
// hour < 10 ? '0' + date.getHours() : date.getHours()
console.log('当前时间的小时 ', hour)
const minute = date.getMinutes()
// const minute = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
return [hour, minute]
}
}
}
</script>
<style lang="scss" scoped>
picker-view {
width: 100%;
height: 600rpx;
margin-top: 20rpx;
}
.center {
display: flex;
justify-content: center;
align-items: center;
}
.item {
line-height: 100rpx;
text-align: center;
}
.win-container {
bottom: 0;
width: 100%;
font-size: 32rpx;
@extend .center;
position: fixed;
z-index: 20;
left: 0;
.win-mask {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
z-index: 20;
position: fixed;
top: 0;
left: 0;
bottom: 0;
}
.win-content {
width: 100%;
max-height: 80vh;
position: absolute;
overflow: auto;
bottom: 0;
left: 0;
// @extend .center;
background-color: #FFFFFF;
z-index: 21;
border-radius: 32rpx 32rpx 0 0;
.operation-title {
@extend .center;
height: 96rpx;
font-size: 32rpx;
font-weight: bold;
view {
flex: 1;
text-align: center;
}
.title {
font-size: 36rpx;
}
.cancel {
color: #666666;
}
.confirm {
color: #2E4CFF;
}
}
}
}
</style>
组件使用:
只展示部分,其他的自己补全
<date-picker :visible.sync="visibleDate" :first-day="startDay" @change="getCheckDate" />
<time-picker :visible.sync="visibleTime" :is-this-today="isThisToday" @change="getCheckTime" />
import TimePicker from '@/components/modal-v2/time-picker'
import DatePicker from '@/components/modal-v2/date-picker.vue'
components: {
TimePicker,
DatePicker
},
// 打开日期弹窗
selectDate() {
this.visibleDate = true
},
// 打开时间弹窗
selectTime() {
this.visibleTime = true
},
// 选择日期
getCheckDate(val) {
const date = val.join('-')
console.log('getCheckDate', val, '传递回去的日期', date)
this.$emit('dateSelect', date)
if (date === this.getDate('start')) { // 如果选择的日期是当天的话
this.isThisToday = true // 告诉组件选择了今天时间得限制
// 判断当前时间是否符合时间段
if (this.checkAuditTime('07:00', '18:00')) {
this.time = ''
this.$emit('timeSelect', '')
} else {
// this.startTime = '08:00'
}
} else {
this.isThisToday = false // 告诉组件选择了今天时间得限制
}
this.date = val[0] + '年' + val[1] + '月' + val[2] + '日'
},
// 时间弹窗选择了时间
getCheckTime(time) {
this.$emit('timeSelect', time)
const selectTime = time
this.time = selectTime.split(':')[0] + '时' + selectTime.split(':')[1] + '分'
}