picker-view 是 UniApp 中用于展示和选择数据的组件。它适用于创建多列选择器,类似于 iOS 和 Android 系统中的选择器视图。以下是 picker-view 的详细介绍,包括用法、属性和事件。
一 用法
<template>
<view>
<picker-view :value="value" @change="onChange" :indicator-style="indicatorStyle">
<picker-view-column v-for="(column, index) in columns" :key="index">
<view v-for="(item, itemIndex) in column" :key="itemIndex">{{ item }}</view>
</picker-view-column>
</picker-view>
</view>
</template>
<script>
export default {
data() {
return {
value: [0, 0], // 选中的值对应列中的索引
columns: [ // 列数据
['Option 1', 'Option 2', 'Option 3'],
['Item 1', 'Item 2', 'Item 3']
],
indicatorStyle: 'height: 50px; line-height: 50px;' // 指示器样式
};
},
methods: {
onChange(e) {
this.value = e.detail.value; // 更新选中的值
console.log('Selected value:', this.value);
}
}
};
</script>
<style scoped>
/* 可以根据需要添加自定义样式 */
</style>
二 主要属性
- value: 数组,表示当前选中的索引值。数组的长度应与 columns 的列数一致。例如,如果有两列,每列的选项数组长度分别为 3 和
3,则 value 应该是 [0, 0] 表示两列的默认选中项索引。 - indicator-style: 字符串,用于设置选择器的指示器样式。可以设置如高度、背景颜色等样式。
三 主要事件
change: 当用户选择了新项时触发。事件对象的 detail.value 是更新后的选中值数组。例如:
onChange(e) {
this.value = e.detail.value;
console.log('Selected value:', this.value);
}
- picker-view-column 是 picker-view 的子组件,每个 picker-view-column 代表一个列。
- v-for 指令用于遍历 columns 和列中的选项数据。
- e.detail.value 是一个数组,表示用户选择的每一列的索引。
四 应用场景
- 选择日期和时间
- 选择地区(省市区)
- 多级分类选择
五 案例
需求 :购买商品时,可以选择取货时间,点击向右的箭头可以显示选择预约取货时间弹窗。第一次进入弹窗,默认回显当前时间,选择时间后,回显选择的时间
父组件在打开弹框时,会传一个当前时间给子组件,子组件在初始化时,根据当前时间进行回显。
根据传过来的时间,拿到月,时,分,然后分别在days,hours,minutes中找到对应的index,在分别把index push到value中
let dayIndex = this.days.findIndex((item) => item === objTimeDay);
let hourIndex = this.hours.findIndex((item) => item === objTimeHour);
let minuteIndex = this.minutes.findIndex((item) => item === objTimeMinute);
if (dayIndex > -1) {
this.value[0] = dayIndex;
}
if (hourIndex > -1) {
this.value[1] = hourIndex;
}
if (minuteIndex > -1) {
this.value[2] = minuteIndex;
}
完整代码
父组件
// 引用
import selectTime from './selectTime/index.vue';
//注册
components: { selectAddress, selectShop, selectTime },
//使用
<select-time ref="selectTime" @getSelectTime="getSelectTime"></select-time>
openSelectTimePopup() {
this.$refs.selectTime.open(this.selectTimeInfo);
},
// 自定义事件
getSelectTime(obj) {
this.selectTimeInfo = obj;
},
selectTime 弹窗
<template>
<uni-popup ref="selectTime" type="bottom" :maskClick="true">
<view class="main">
<view class="main-header">
<view class="main-header-title">预约取货时间</view>
<view class="main-header-image" @click="close">
<image src="@/static/image/cart/sureOrder/close.png"></image>
</view>
</view>
<view class="main-time">
<picker-view v-if="visible" :indicator-style="indicatorStyle" :value="value" @change="bindChange" class="picker-view">
<picker-view-column>
<view class="item" v-for="(item, index) in days" :key="index">{{ item }}</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item, index) in hours" :key="index">{{ item }}</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item, index) in minutes" :key="index">{{ item }}</view>
</picker-view-column>
</picker-view>
</view>
<view class="main-button" @click="confirm">确认</view>
</view>
</uni-popup>
</template>
<script>
export default {
data() {
return {
days: [],
hours: [],
minutes: [],
day: '',
hour: '',
minute: '',
visible: true,
value: [],
indicatorStyle: `height: 50px;`,
selectTimeInfo: {
name: '',
time: ''
}
};
},
methods: {
confirm() {
this.day = this.days[this.value[0]];
this.hour = this.hours[this.value[1]];
this.minute = this.minutes[this.value[2]];
this.selectTimeInfo.name = this.day + ' ' + this.hour + ':' + this.minute;
let currentDate = new Date();
currentDate.setDate(currentDate.getDate() + this.value[0]);
let selectYear = currentDate.getFullYear();
let selectTimeMonth = currentDate.getMonth() + 1 < 10 ? '0' + (currentDate.getMonth() + 1) : currentDate.getMonth() + 1;
let selectTimeDay = currentDate.getDate() < 10 ? '0' + currentDate.getDate() : currentDate.getDate();
let time = selectYear + '-' + selectTimeMonth + '-' + selectTimeDay + ' ' + this.hour + ':' + this.minute;
this.selectTimeInfo.time = time.slice(0, 16)+':' + '00';
this.$emit('getSelectTime', this.selectTimeInfo);
this.close();
},
init(obj) {
// day
for (var i = 0; i < 5; i++) {
let date = new Date();
let day;
if (i === 0) {
day = '今天';
} else if (i === 1) {
day = '明天';
} else {
date.setDate(date.getDate() + i);
let month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
let d = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
day = month + '月' + d + '日';
}
this.days.push(day);
}
let currentDate = new Date();
let currentMonth = currentDate.getMonth() + 1;
let currentDay = currentDate.getDate();
let selectTime = obj.time;
let objTimeDate = new Date(selectTime);
let selectMonth = objTimeDate.getMonth() + 1;
let selectDay = objTimeDate.getDate();
let objTimeDay;
if (currentMonth === selectMonth && currentDay === selectDay) {
objTimeDay = '今天';
} else if (currentMonth === selectMonth && currentDay + 1 === selectDay) {
objTimeDay = '明天';
} else {
let month = selectMonth < 10 ? '0' + selectMonth + '月' : selectMonth + '月';
let day = selectDay < 10 ? '0' + selectDay + '日' : selectDay + '日';
objTimeDay = month + day;
}
let objTimeHour = objTimeDate.getHours() < 10 ? '0' + objTimeDate.getHours() : objTimeDate.getHours();
let objTimeMinute = objTimeDate.getMinutes() < 10 ? '0' + objTimeDate.getMinutes() + '分' : objTimeDate.getMinutes() + '分';
this.hours = this.getHoursRange(0, 24);
this.minutes = this.getMinuteRange(0, 61);
let dayIndex = this.days.findIndex((item) => item === objTimeDay);
let hourIndex = this.hours.findIndex((item) => item === objTimeHour);
let minuteIndex = this.minutes.findIndex((item) => item === objTimeMinute);
if (dayIndex > -1) {
this.value[0] = dayIndex;
}
if (hourIndex > -1) {
this.value[1] = hourIndex;
}
if (minuteIndex > -1) {
this.value[2] = minuteIndex;
}
},
getHoursRange(startHour, endHour) {
const hours = [];
for (let i = startHour; i <= endHour; i++) {
let hour = i < 10 ? '0' + i : i;
hours.push(hour);
}
return hours;
},
getMinuteRange(startMinute, endMinute) {
let minutes = [];
for (var i = startMinute; i < endMinute; i++) {
let minute = i < 10 ? '0' + i + '分' : i + '分';
minutes.push(minute);
}
return minutes;
},
bindChange(e) {
const val = e.detail.value;
this.value[0] = val[0];
this.value[1] = val[1];
this.value[2] = val[2];
},
open(obj) {
this.$refs.selectTime.open();
this.init(obj);
},
close() {
this.$refs.selectTime.close();
}
}
};
</script>
<style lang="scss" scoped>
.main {
width: 100%;
height: 732rpx;
border-radius: 32rpx 32rpx 0px 0px;
background-color: #fff;
box-sizing: border-box;
.main-header {
padding: 40rpx 0 0 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
.main-header-title {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: bold;
font-size: 36rpx;
color: #333333;
text-align: left;
font-style: normal;
text-transform: none;
}
.main-header-image {
width: 48rpx;
height: 48rpx;
margin-right: 40rpx;
image {
width: 100%;
height: 100%;
}
}
}
.main-time {
width: 100%;
height: 400rpx;
margin-top: 80rpx;
.picker-view {
width: 100%;
height: 300rpx;
margin-top: 20rpx;
}
.item {
line-height: 100rpx;
text-align: center;
}
}
.main-button {
width: 496rpx;
height: 80rpx;
background: #c11920;
border-radius: 80rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 32rpx;
color: #ffffff;
line-height: 80rpx;
text-align: center;
font-style: normal;
text-transform: none;
margin: 40rpx auto 0 auto;
}
}
</style>
如果需要设置不能选择之前的时间,可以拿到当前时间的时,分,来设置
if (objTimeDay === '今天') {
this.hours = this.getHoursRange(currentHour, 24);
this.minutes = this.getMinuteRange(currentMinute, 61);
} else {
this.hours = this.getHoursRange(0, 24);
this.minutes = this.getMinuteRange(0, 61);
}
getHoursRange(startHour, endHour) {
const hours = [];
for (let i = startHour; i <= endHour; i++) {
let hour = i < 10 ? '0' + i : i;
hours.push(hour);
}
return hours;
},
getMinuteRange(startMinute, endMinute) {
let minutes = [];
for (var i = startMinute; i < endMinute; i++) {
let minute = i < 10 ? '0' + i + '分' : i + '分';
minutes.push(minute);
}
return minutes;
},