<template> <view class="simple-address" v-if="showPopup"> <!-- 遮罩层 --> <view class="simple-address-mask" v-if="maskClick" :class="[ani + '-mask', animation ? 'mask-ani' : '']" :style="{ 'background-color': maskBgColor }" @tap="hideMask(true)" ></view> <!-- 省市区 --> <view class="simple-address-content simple-address--fixed" :class="[type, ani + '-content', animation ? 'content-ani' : '']"> <view class="simple-address__header"> <view class="simple-address__header-btn-box" @click="pickerCancel"> <text class="simple-address__header-text" :style="{ color: cancelColor, fontSize: btnFontSize }">取消</text> </view> <view class="simple-address__header-btn-box" @click="pickerConfirm"> <text class="simple-address__header-text" :style="{ color: confirmColor, fontSize: btnFontSize }">确定</text> </view> </view> <view class="simple-address__box"> <picker-view indicator-style="height: 70rpx;" class="simple-address-view" :value="pickerValue" @change="pickerChange"> <picker-view-column> <!-- #ifndef APP-NVUE --> <view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.name }}</view> <!-- #endif --> <!-- #ifdef APP-NVUE --> <text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.name }}</text> <!-- #endif --> </picker-view-column> <picker-view-column> <!-- #ifndef APP-NVUE --> <view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.name }}</view> <!-- #endif --> <!-- #ifdef APP-NVUE --> <text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.name }}</text> <!-- #endif --> </picker-view-column> <picker-view-column> <!-- #ifndef APP-NVUE --> <view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.name }}</view> <!-- #endif --> <!-- #ifdef APP-NVUE --> <text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.name }}</text> <!-- #endif --> </picker-view-column> </picker-view> </view> </view> </view> </template> <script> import { getProvince, getCityByPro, getDistrictByCity } from '@/api/data.js' export default{ name: 'Address', props: { // 是否允许点击遮罩层关闭 maskClick: { type: Boolean, default: true }, // 是否开启动画 animation: { type: Boolean, default: true }, // 遮罩层背景颜色 maskBgColor: { type: String, default: 'rgba(0, 0, 0, 0.4)' //背景颜色 rgba(0, 0, 0, 0.4) 为空则调用 uni.scss }, /* 弹出层类型,可选值; 暂时只支持底部弹出 bottom:底部弹出层 */ type: { type: String, default: 'bottom' }, cancelColor: { type: String, default: '' // 取消按钮颜色 }, confirmColor: { type: String, default: '' // 确认按钮颜色 }, fontSize: { type: String, default: '28rpx' // picker-item字体大小 }, btnFontSize: { type: String, default: '' // 按钮的字体大小 }, }, data(){ return{ showPopup: false, // 是否显示省市区选择 ani: '', pickerValue: [0, 0, 0], // 默认值下标 pickerId: [], // 省市区默认值id provinceDataList: [], // 省数据列表 cityDataList: [], // 市数据列表 areaDataList: [], // 区数据列表 isFirst: false, // 是否首次进入组件 } }, methods: { // 初始化 init(){ this.provinceDataList = [] this.cityDataList = [] this.areaDataList = [] this.isFirst = false }, // 点击遮罩层关闭选择省市区 hideMask() { this._$emit('onCancel') this.close() }, // 打开省市区picker open(idArr) { // 初始化数据 this.init() this.pickerId = idArr // idArr 省市区默认id if(this.pickerId && this.pickerId.length > 0){ // 获取省下拉 this.getProvinceList(idArr) }else{ // 获取省下拉 this.getProvinceList() } this.showPopup = true this.$nextTick(() => { setTimeout(() => { this.ani = 'simple-' + this.type }, 100) }); }, // 关闭省市区picker close(type) { if (!this.maskClick && type) return this.ani = '' this.$nextTick(() => { setTimeout(() => { this.showPopup = false }, 300) }) }, // 取消按钮 pickerCancel() { this._$emit('onCancel') this.close() }, // 确定按钮 pickerConfirm() { this._$emit('onConfirm') if(!this.isFirst){ // 首次 this.isFirst = true } this.close() }, // 省市区 change pickerChange(e) { const _this = this let changePickerValue = e.detail.value if (this.pickerValue[0] !== changePickerValue[0]) { if(this.pickerId && this.pickerId.length > 0 && this.isFirst){ // 获取市下拉 this.getCityList(this.pickerId[0], this.pickerId) }else{ // 第一级发生滚动,省 change重置市区下拉数据 this.getCityList(this.provinceDataList[changePickerValue[0]].id) changePickerValue[1] = 0 changePickerValue[2] = 0 } } else if (this.pickerValue[1] !== changePickerValue[1]) { if(this.pickerId && this.pickerId.length > 0 && this.isFirst){ // 获取市下拉 this.getAreaList(this.pickerId[1], this.pickerId) }else{ // 第二级滚动,市 change重置区县下拉数据 this.getAreaList(this.cityDataList[changePickerValue[1]].id) changePickerValue[2] = 0 } } this.pickerValue = changePickerValue // setTimeout解决由于省市区接口请求数据有延缓导致获值报错 setTimeout(()=>{ _this._$emit('onChange') },1000) }, _$emit(emitName) { let pickObj = { label: this._getLabel(), value: this.pickerValue, cityCode: this._getCityCode(), areaCode: this._getAreaCode(), provinceCode: this._getProvinceCode(), labelArr: this._getLabel().split('-') } this.$emit(emitName, pickObj) }, _getLabel() { // name报错未发现页面影响(由于省市区接口请求数据延缓) let pcikerLabel = this.provinceDataList[this.pickerValue[0]].name + '-' + this.cityDataList[this.pickerValue[1]].name + '-' + this.areaDataList[this.pickerValue[2]].name return pcikerLabel }, _getCityCode() { return this.cityDataList[this.pickerValue[1]].id }, _getProvinceCode() { return this.provinceDataList[this.pickerValue[0]].id }, _getAreaCode() { return this.areaDataList[this.pickerValue[2]].id }, // 获取省下拉数据 getProvinceList(idArr){ const _this = this getProvince().then(res => { if (res.code == 200 || res.status == 204 || res.status == 200) { _this.provinceDataList = res.data || [] // 省下拉数据 // 判断是否有默认值 if(idArr){ _this.getCityList(idArr[0], idArr) _this.getAreaIndArr(idArr) }else{ // 默认省数据第一条下的市下拉数据 _this.getCityList(_this.provinceDataList[0].id) } } else { _this.provinceDataList = [] } }) }, // 获取城市列表 getCityList (val, idArr) { const _this = this _this.cityDataList = [] _this.areaDataList = [] if (val != null && val != '') { getCityByPro({id: val}).then(res => { if (res.code == 200 || res.status == 204 || res.status == 200) { _this.cityDataList = res.data || [] // 市下拉数据 // 判断是否有默认值 if(idArr){ _this.getAreaList(idArr[1], idArr) _this.getAreaIndArr(idArr) }else{ // 默认市数据第一条下的区县下拉数据 _this.getAreaList(_this.cityDataList[0].id) } } else { _this.cityDataList = [] } }) } }, // 获取区县列表 getAreaList (val, idArr) { const _this = this this.areaDataList = [] if (val != null && val != '') { getDistrictByCity({id: val}).then(res => { if (res.code == 200 || res.status == 204 || res.status == 200) { _this.areaDataList = res.data || [] // 判断是否有默认值 if(idArr){ _this.getAreaIndArr(idArr) } } else { _this.areaDataList = [] } }) } }, // 根据id 获取省市区 下标值 getAreaIndArr(idArr){ const _this = this const provinceInd = _this.provinceDataList.findIndex(res => res['id'] == idArr[0]) const cityInd = _this.cityDataList.findIndex(res => res['id'] == idArr[1]) const districtInd = _this.areaDataList.findIndex(res => res['id'] == idArr[2]) setTimeout(()=>{ _this.pickerValue = [provinceInd, cityInd, districtInd] },100) // console.log(_this.pickerValue,'_this.pickerValue') } } } </script> <style lang="scss" scoped> .simple-address { /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex-direction: column; } .simple-address-mask { position: fixed; bottom: 0; top: 0; left: 0; right: 0; transition-property: opacity; transition-duration: 0.3s; opacity: 0; /* #ifndef APP-NVUE */ z-index: 99; /* #endif */ } .mask-ani { transition-property: opacity; transition-duration: 0.2s; } .simple-bottom-mask { opacity: 1; } .simple-center-mask { opacity: 1; } .simple-address--fixed { position: fixed; bottom: 0; left: 0; right: 0; transition-property: transform; transition-duration: 0.3s; transform: translateY(460rpx); /* #ifndef APP-NVUE */ z-index: 99; /* #endif */ } .simple-address-content { background-color: #ffffff; } .simple-content-bottom { bottom: 0; left: 0; right: 0; transform: translateY(500rpx); } .content-ani { transition-property: transform, opacity; transition-duration: 0.2s; } .simple-bottom-content { transform: translateY(0); } .simple-center-content { transform: scale(1); opacity: 1; } .simple-address__header { position: relative; /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex-direction: row; flex-wrap: nowrap; justify-content: space-between; border-bottom-color: #f2f2f2; border-bottom-style: solid; border-bottom-width: 1rpx; } .simple-address--fixed-top { /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex-direction: row; justify-content: space-between; border-top-color: $uni-border-color; border-top-style: solid; border-top-width: 1rpx; } .simple-address__header-btn-box { /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex-direction: row; align-items: center; justify-content: center; height: 70rpx; } .simple-address__header-text { text-align: center; font-size: $uni-font-size-base; color: #1aad19; line-height: 70rpx; padding-left: 40rpx; padding-right: 40rpx; } .simple-address__box { position: relative; } .simple-address-view { position: relative; bottom: 0; left: 0; /* #ifndef APP-NVUE */ width: 100%; /* #endif */ /* #ifdef APP-NVUE */ width: 750rpx; /* #endif */ height: 408rpx; background-color: rgba(255, 255, 255, 1); } .picker-item { text-align: center; line-height: 70rpx; text-overflow: ellipsis; font-size: 28rpx; } </style>