ns-picker选择器
<template>
<view>
<view class="picker-modal over-max-width" v-if="showPicker"></view>
<view class="picker-content over-max-width"
:style="{ transform: showPicker ? 'translateY(0)' : 'translateY(100%)' }">
<view class="picker-header flex-justify">
<view class="text-other" @click="cancel">取消</view>
<view class="title">{{ title }}</view>
<view class="confirm" @click="confirm">确定</view>
</view>
<picker-view mask-style="background:transparent" indicator-style="height: 90rpx;" class="picker-view"
:value="pickerValue" @change="changePicker" @pickstart="pickstart" @pickend="pickend"
v-if="'selector' === mode">
<picker-view-column>
<view class="picker-item" :class="pickerValue[0] === index ? 'text-current' : 'text-other'"
v-for="(item, index) in pickerList" :key="index">
{{ item.label }}
</view>
</picker-view-column>
</picker-view>
<picker-view mask-style="background:transparent" indicator-style="height: 90rpx;" class="picker-view"
:value="pickerValue" @change="changePicker" @pickstart="pickstart" @pickend="pickend"
v-if="'date' === mode">
<picker-view-column>
<view class="picker-item" :class="pickerValue[0] === index ? 'text-current' : 'text-other'"
v-for="(item, index) in years" :key="index">{{ item }}年</view>
</picker-view-column>
<picker-view-column>
<view class="picker-item" :class="pickerValue[1] === index ? 'text-current' : 'text-other'"
v-for="(item, index) in months" :key="index">{{ item }}月</view>
</picker-view-column>
<picker-view-column v-if="'days' === fields">
<view class="picker-item" :class="pickerValue[2] === index ? 'text-current' : 'text-other'"
v-for="(item, index) in days" :key="index">{{ item }}日</view>
</picker-view-column>
</picker-view>
<picker-view mask-style="background:transparent" indicator-style="height: 90rpx;" class="picker-view"
:value="pickerValue" @change="changePicker" @pickstart="pickstart" @pickend="pickend"
v-if="'multiSelector' === mode">
<picker-view-column v-for="(list,index) in pickerList" :key="index">
<view class="picker-item" :class="pickerValue[index] === index1 ? 'text-current' : 'text-other'"
v-for="(item, index1) in list" :key="index1">{{ item }}</view>
</picker-view-column>
</picker-view>
</view>
</view>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ''
},
pickerList: {
type: Array
},
mode: {
type: String,
default: 'selector'
},
fields: {
type: String,
default: 'month'
},
value: {
type: Array
},
type: {
type: String,
default: 'all'
}
},
watch: {
pickerList() {},
value() {
this.pickerValue = this.value
}
},
data() {
let date = new Date();
if ('current' === this.type) {
let now = new Date();
// 5天后
date = new Date(now.getTime() + 5 * 24 * 3600 * 1000);
}
const years = [];
const year = date.getFullYear();
const months = [];
const month = date.getMonth() + 1;
const days = [];
const day = date.getDate();
let pickerValue = 'multiSelector' === this.mode ? this.value : ('date' === this.mode ? [9999, month - 1,
day - 1
] : [0]);
if ('current' === this.type) {
years.push(year)
for (let i = 1; i <= 12; i++) {
if (i >= month) {
months.push(i < 10 ? ('0' + i) : i);
}
}
pickerValue = 'multiSelector' === this.mode ? this.value : ('date' === this.mode ? [0, 0, 0] : [
0
]);
} else {
for (let i = 1990; i <= date.getFullYear(); i++) {
years.push(i);
}
for (let i = 1; i <= 12; i++) {
months.push(i < 10 ? ('0' + i) : i);
}
}
for (let i = 1; i <= 31; i++) {
days.push(i < 10 ? ('0' + i) : i);
}
return {
day: day,
month: month,
alldays: days,
years: years,
months: months,
pickerValue: pickerValue,
days: [],
isMoving: false,
showPicker: false
};
},
options: {
styleIsolation: 'shared'
},
methods: {
cancel() {
this.showPicker = false;
},
open() {
this.showPicker = true;
this.daysChange()
},
pickstart(e) {
this.isMoving = true;
},
pickend() {
this.isMoving = false;
},
confirm() {
if (this.isMoving) {
uni.$showMsg('滚动选择中,请稍后确定');
return;
}
if ('selector' === this.mode) {
this.$emit('onConfirm', this.pickerValue[0]);
}
if ('date' === this.mode) {
if ('month' === this.fields) {
this.$emit('onConfirm', this.years[this.pickerValue[0]] + '-' + this.months[this.pickerValue[
1]]);
} else {
this.$emit('onConfirm', this.years[this.pickerValue[0]] + '-' + this.months[this.pickerValue[
1]] + '-' + this.days[this.pickerValue[2]]);
}
}
if ('multiSelector' === this.mode) {
this.$emit('onConfirm', this.pickerValue)
}
this.cancel();
},
daysChange() {
/// 各月份的天数处理
const thirtys_plus = [1, 3, 5, 7, 8, 10, 12]
if (thirtys_plus.includes(Number(this.months[this.pickerValue[1]]))) {
this.days = this.alldays
} else if (2 === Number(this.months[this.pickerValue[1]])) {
this.days = this.alldays.filter((item, index) => index < 28)
} else {
this.days = this.alldays.filter((item, index) => index < 30)
}
// 当前月份不能选当天之前的日期
if ('current' === this.type && this.month === Number(this.months[this.pickerValue[1]])) {
this.days = this.days.filter((item, index) => index >= this.day - 1)
} else {
this.days = this.days
}
},
changePicker(e) {
const oldValue = this.pickerValue;
this.pickerValue = e.detail.value;
if ('date' === this.mode) {
this.daysChange()
}
if ('multiSelector' === this.mode) {
oldValue.forEach((item, index) => {
if (item !== this.pickerValue[index]) {
this.$emit('columnChange', {
column: index,
value: this.pickerValue[index]
})
}
})
}
}
}
};
</script>
<style lang="scss">
.picker-modal {
z-index: 90;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
}
.picker-content {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 99;
transition: all 0.3s;
border-radius: 30rpx 30rpx 0 0;
padding: 30rpx 20rpx;
box-sizing: border-box;
background: #393A3E;
.picker-header {
height: 100rpx;
line-height: 100rpx;
position: absolute;
top: 0;
left: 40rpx;
right: 40rpx;
.confirm {
color: $color-3;
}
.text-other {
color: $color-4;
}
.title {
font-size: 32rpx;
font-weight: bold;
}
}
.indecator {
font-size: 50rpx;
}
.picker-view {
position: relative;
top: 60rpx;
left: 0;
right: 0;
height: 490rpx;
.text-current {
color: $color-3;
}
.text-other {
color: #ACABA5;
}
.picker-item {
line-height: 90rpx;
// #ifdef MP-WEIXIN
line-height: 70rpx;
// #endif
text-align: center;
text-overflow: ellipsis;
}
}
}
::v-deep .uni-picker-view-indicator{
border-top:1rpx solid #D8D8D8;
border-bottom:1rpx solid #D8D8D8;
}
</style>
pick-regions地址选择组件
<template>
<view class="pick-regions">
<ns-picker ref="logistics" mode="multiSelector" :value="multiIndex" :pickerList="multiArray"
@onConfirm="handleValueChange" @columnChange="handleColumnChange"></ns-picker>
</view>
</template>
<script>
export default {
props: {
defaultRegions: {
type: Array
},
selectArr: {
type: String
}
},
data() {
return {
pickerValueArray: [],
cityArr: [],
districtArr: [],
multiIndex: [0, 0, 0],
isInitMultiArray: false,
// 是否加载完默认地区
isLoadDefaultAreas: false
};
},
watch: {
defaultRegions: {
handler(arr, oldArr = []) {
// 避免传的是字面量的时候重复触发
if (arr.length != this.selectArr || arr.join('') === oldArr.join('')) return;
this.handleDefaultRegions();
},
immediate: true
}
},
computed: {
multiArray() {
if (!this.isLoadDefaultAreas) return;
var arr = this.pickedArr.map(arr => arr.map(item => item.label));
return arr;
},
pickedArr() {
// 进行初始化
if (this.isInitMultiArray) {
if (this.selectArr == '2') {
return [this.pickerValueArray[0], this.pickerValueArray[1]];
} else {
return [this.pickerValueArray[0], this.pickerValueArray[1], this.pickerValueArray[2]];
}
}
if (this.selectArr == '2') {
return [this.pickerValueArray[0], this.cityArr];
} else {
return [this.pickerValueArray[0], this.cityArr, this.districtArr];
}
}
},
created() {
this.getDefaultAreas(0, {
type: 1
});
},
methods: {
open() {
this.$refs.logistics.open()
},
async handleColumnChange(e) {
this.isInitMultiArray = false;
let col = e.column;
let row = e.value;
this.multiIndex[col] = row;
switch (col) {
case 0:
//选择省,加载市、区县
this.cityArr = await this.getAreasAsync(this.pickerValueArray[0][this.multiIndex[col]]
.value);
this.districtArr = await this.getAreasAsync(this.cityArr[0].value);
break;
case 1:
//选择市,加载区县
this.districtArr = await this.getAreasAsync(this.cityArr[this.multiIndex[col]].value);
break;
case 2:
if (!this.cityArr.length) this.cityArr = await this.getAreasAsync(this.pickerValueArray[0][
0
].value)
if (!this.districtArr.length) this.districtArr = await this.getAreasAsync(this.cityArr[0]
.value);
break;
}
},
handleValueChange(e) {
// 结构赋值
let [index0, index1, index2] = e;
let [arr0, arr1, arr2] = this.pickedArr;
let address = '';
if (this.selectArr == '2') {
address = [arr0[index0], arr1[index1]];
} else {
address = [arr0[index0], arr1[index1], arr2[index2]];
}
this.$emit('getRegions', address);
},
handleDefaultRegions() {
var time = setInterval(() => {
if (!this.isLoadDefaultAreas) return;
this.isInitMultiArray = false;
for (let i = 0; i < this.defaultRegions.length; i++) {
for (let j = 0; j < this.pickerValueArray[i].length; j++) {
// 匹配省
if ((this.defaultRegions[i] == this.pickerValueArray[i][j].value || this
.defaultRegions[i] == this.pickerValueArray[i][j].label) && this
.pickerValueArray[i][j].level == 1) {
// 设置选中省
this.$set(this.multiIndex, i, j);
// 查询市
this.getAreas(this.pickerValueArray[i][j].value, data => {
this.cityArr = data;
for (let k = 0; k < this.cityArr.length; k++) {
if (this.defaultRegions[1] == this.cityArr[k].value || this
.defaultRegions[1] == this.cityArr[k].label) {
// 设置选中市
this.$set(this.multiIndex, 1, k);
// 查询区县
this.getAreas(this.cityArr[k].value, data => {
this.districtArr = data;
// 设置选中区县
for (let u = 0; u < this.districtArr
.length; u++) {
if (this.defaultRegions[2] == this
.districtArr[u].value || this
.defaultRegions[2] == this.districtArr[
u].label) {
this.$set(this.multiIndex, 2, u);
this.handleValueChange({
detail: {
value: [j, k, u]
}
});
break;
}
}
});
break;
}
}
});
}
}
}
if (this.isLoadDefaultAreas) clearInterval(time);
}, 100);
},
getDefaultAreas(pid, obj) {
this.$api.sendRequest({
url: 'xxx',
data: {
type: obj.type,
region_id: pid
},
success: res => {
if (200 === res.code) {
var data = [];
var selected = undefined;
res.data.forEach((item, index) => {
if (obj != undefined) {
if (obj.type == 1 && obj.id != undefined) {
selected = obj.id;
} else if (obj.type == 2 && obj.city_id != undefined) {
selected = obj.city_id;
} else if (obj.type == 3 && obj.district_id != undefined) {
selected = obj.district_id;
}
}
if (selected == undefined && index == 0) {
selected = item.id;
}
data.push({
value: item.id,
label: item.name,
level: item.level
});
});
this.pickerValueArray[obj.type - 1] = data;
if (obj.type + 1 < 4) {
obj.type++;
this.getDefaultAreas(selected, obj);
} else {
this.isInitMultiArray = true;
this.isLoadDefaultAreas = true;
}
}
}
});
},
// 同步获取地区
async getAreasAsync(pid) {
let res = await this.$api.sendRequest({
url: 'xxx',
data: {
type: 2,
region_id: pid
},
async: false
});
if (200 === res.code) {
var data = [];
res.data.forEach((item, index) => {
data.push({
value: item.id,
label: item.name,
level: item.level
});
});
return data;
}
},
// 异步获取地区
getAreas(pid, callback) {
this.$api.sendRequest({
url: 'xxx',
data: {
type: 3,
region_id: pid
},
success: res => {
if (200 === res.code) {
var data = [];
res.data.forEach((item, index) => {
data.push({
value: item.id,
label: item.name,
level: item.level
});
});
if (callback) callback(data);
}
}
});
},
}
};
</script>
使用:
<pick-regions ref="picker" :default-regions="defaultRegions" @getRegions="handleGetRegions"></pick-regions>
export default{
data(){
return {
defaultRegions: [] // [province_id, city_id,district_id]
}
},
methods:{
// 获取选择的地区
handleGetRegions(regions) {
},
}
}
效果图如下: