小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
uniapp 打造自用组件库 (七) 时间选择器
前言
本文将带领读者使用uniapp封装一些常用组件,方便日后开发时重复使用,当然文中封装的组件不可能适配所有应用场景,但是我希望读者可以跟着我的思路实现出来,然后可以在此基础上优化改进为自己合适的,本人一个前端小菜鸡,希望大佬们可以不吝赐教,也是对我的技术水平的提升
时间选择器
需求
在开发的项目中,尤其是数据分析相关功能,经常会有多种时间筛选功能,需要按月、按年、按照时间范围来筛选,于是就封装了本组件,用于应对多种情况,划动选择后,点击确定后回调(可自行修改为收起时触发回调),返回类型,返回时间
效果展示
应用效果
应用代码
<view>
<button type="default" @tap="isShow = true">选择时间 {{date}}</button>
<Yselector :show.sync='isShow' @change='change'></Yselector>
</view>
export default {
data() {
return {
isShow:false,
date:'',
}
},
methods: {
change(info){
console.log('返回数据====>',info)
this.date = ''
for(let item of info){
this.date = `${this.date} ${item}`
}
},
}
}
实现思路
利用uniapp的自定义选择器组件,在用户切换顶部按钮时生成选择项,然后选择完成后回调数据
完整实现代码
<template>
<view class="bgBox">
<view class="bg" @tap.stop="hide" :style="{height:show?'1000rpx':'0rpx'}">
<view class="main" @tap.stop :style="{height:show?'600rpx':'0rpx'}">
<view class="head">
<view class="item" v-for="(i,index) in items" @tap="tapItems(index)" :style="{backgroundColor:itemsIndex == index?color:'#fff',color:itemsIndex == index?'#fff':'#333'}">
{{i}}
</view>
</view>
<view class="body">
<picker-view :value='defaultDate' @change='change' :indicator-style='"padding:5px 0; border-top: 2px "+color+" solid;border-bottom: 2px "+color+" solid;"'>
<picker-view-column :style="{marginLeft:index == 3?'30rpx':'10rpx' }" :key='index' v-for="(itemList,index) in infoList">
<view :key='ind' v-for="(i,ind) in itemList">{{i}}</view>
</picker-view-column>
</picker-view>
</view>
<view class="foot" @tap="changeHide">
<view>确定</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'Yselector',
props: {
show: { //控制组件开关
type: Boolean,
default: false
},
color: {
type: String,
default: '#1E5EFF'
}
},
data() {
return {
itemsIndex: 0,
items: [
'天',
'月度',
'年度',
'时间范围',
'全部',
],
infoList: [],
defaultDate: [],
Maindate: '',
Maindate1:'',
};
},
watch:{
show(){
if(this.show){
this.tapItems(0)
}
}
},
methods: {
getList(thisTime,type=true) {
if(type){
this.Maindate = thisTime
}else{
this.Maindate1 = thisTime
}
let timeList = thisTime.split('-')
let ydate = new Date()
let year = ydate.getFullYear()
let day = new Date(parseInt(timeList[0]), parseInt(timeList[1]), 0); //获取当月有多少天
let date = day.getDate()
let yearList = []
let monthList = []
let dateList = []
for (let i = 2000; i <= parseInt(year); i++) {
yearList = [...yearList, i]
}
for (let i = 1; i <= parseInt(12); i++) {
monthList = [...monthList, i]
}
for (let i = 1; i <= parseInt(date); i++) {
dateList = [...dateList, i]
}
let mylist = [
yearList,
monthList,
dateList
]
let infoList = []
let yearIndex = yearList.indexOf(parseInt(timeList[0]))
let defaultDate = []
for (let i in timeList) {
if (i == 0) {
defaultDate = [yearIndex]
} else {
defaultDate = [...defaultDate, parseInt(timeList[i]) - 1]
}
infoList = [...infoList, mylist[i]]
}
return {
defaultDate,
infoList
}
},
change({
detail
}) {
let time = ''
let time1 = ''
for (let i in detail.value) {
if (i < 3) {
time += time ? `-${this.infoList[i][detail.value[i]]}` : `${this.infoList[i][detail.value[i]]}`
} else {
time1 += time1 ? `-${this.infoList[i][detail.value[i]]}` : `${this.infoList[i][detail.value[i]]}`
}
}
let timeData =[]
let timeData1 =[]
if(time){
timeData = this.getList(time)
}
if(time1){
timeData1 = this.getList(time1,false)
}
let list = timeData1.infoList?[...timeData.infoList,...timeData1.infoList]:[...timeData.infoList]
let defaultDateList = timeData1.infoList?[...timeData.defaultDate,...timeData1.defaultDate]:[...timeData.defaultDate]
this.$set(this, 'defaultDate', defaultDateList)
this.$set(this, 'infoList', list )
},
tapItems(index) {
this.itemsIndex = index
let date = new Date()
if (this.items[index] == '天') {
let time = `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`
let timeData = this.getList(time)
this.$set(this, 'defaultDate', timeData.defaultDate)
this.$set(this, 'infoList', timeData.infoList)
}
if (this.items[index] == '月度') {
let Mydate = `${date.getFullYear()}-${date.getMonth()+1}`
let timeData = this.getList(Mydate)
this.$set(this, 'defaultDate', timeData.defaultDate)
this.$set(this, 'infoList', timeData.infoList)
}
if (this.items[index] == '年度') {
let Mydate = `${date.getFullYear()}`
let timeData = this.getList(Mydate)
this.$set(this, 'defaultDate', timeData.defaultDate)
this.$set(this, 'infoList', timeData.infoList)
}
if (this.items[index] == '时间范围') {
let Mydate = `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`
let timeData = this.getList(Mydate)
let timeData1 = this.getList(Mydate,false)
let list = [...timeData.infoList, ...timeData1.infoList]
let defaultDateList = [...timeData.defaultDate, ...timeData1.defaultDate]
this.$set(this, 'defaultDate', defaultDateList)
this.$set(this, 'infoList', list)
}
if (this.items[index] == '全部') {
let Mydate = `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`
this.Maindate = Mydate
this.changeHide()
}
},
changeHide() {
this.hide()
let list = this.items[this.itemsIndex] == '全部'?[]:this.items[this.itemsIndex] == '时间范围'?[this.Maindate,this.Maindate1]:[this.Maindate]
this.$emit('change', list);
},
hide(e) {
this.$emit('update:show', false);
}
}
};
</script>
<style lang="scss">
.bgBox{
position: relative;
height: 0px;
width: 100%;
}
.bg {
position: absolute;
width: 100%;
height: 600rpx;
left: 0;
top: 100%;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.5) 10%, rgba(0, 0, 0, 0) 90%);
z-index: 998;
transition: 0.2s;
.main {
transition: 0.2s;
width: 100%;
height: 400rpx;
background-color: #fff;
border-radius: 0 0 25upx 25upx;
display: flex;
flex-direction: column;
overflow: hidden;
.head {
display: flex;
padding: 15rpx 30rpx;
.item {
transition: 0.1s;
flex: 1;
font-size: 12px;
margin: 0 10rpx;
text-align: center;
padding: 10rpx 20rpx;
border-radius: 10rpx;
white-space: nowrap;
&:active {
opacity: 0.7;
transform: scale(0.9);
}
}
}
.body {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
picker-view {
margin-left: 20upx;
height: 100%;
picker-view-column {
width: 100rpx;
margin-left: 10upx;
}
view {
font-size: 14px;
font-weight: 400;
color: rgba(51, 51, 51, 1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
}
}
.foot {
display: flex;
padding: 20rpx 30rpx;
view {
flex: 1;
padding: 15rpx 0;
border-radius: 30rpx;
text-align: center;
background-color: #1E5EFF;
color: #FFFFFF;
transition: 0.2s;
&:active {
opacity: 0.7;
transform: scale(0.98);
}
}
}
}
}
</style>