From fe75cffbf3bae6777aa2794fd89fa5dc37f5df8d Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期二, 15 七月 2025 10:11:23 +0800 Subject: [PATCH] 项目初始化 --- src/components/u-city-select/u-city-select.vue | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 265 insertions(+), 0 deletions(-) diff --git a/src/components/u-city-select/u-city-select.vue b/src/components/u-city-select/u-city-select.vue new file mode 100644 index 0000000..6f4eef7 --- /dev/null +++ b/src/components/u-city-select/u-city-select.vue @@ -0,0 +1,265 @@ +<template> + <u-popup :show="modelValue" mode="bottom" :popup="false" :mask="true" :closeable="true" + :safe-area-inset-bottom="true" close-icon-color="#ffffff" :z-index="uZIndex" :maskCloseAble="maskCloseAble" + @close="close"> + <u-tabs v-if="modelValue" :list="genTabsList" :scrollable="true" :current="tabsIndex" @change="tabsChange" + ref="tabs" /> + <view class="area-box"> + <view class="u-flex" :class="{ 'change': isChange }"> + <view class="area-item"> + <view class="u-padding-10 u-bg-gray" style="height: 100%;"> + <scroll-view :scroll-y="true" style="height: 100%"> + <u-cell-group> + <u-cell v-for="(item, index) in provinces" :title="item.label" :arrow="false" + :index="index" :key="index" @click="provinceChange(index)"> + <template v-slot:right-icon> + <u-icon v-if="isChooseP && province === index" size="17" + name="checkbox-mark"></u-icon> + </template> + </u-cell> + </u-cell-group> + </scroll-view> + </view> + </view> + <view class="area-item"> + <view class="u-padding-10 u-bg-gray" style="height: 100%;"> + <scroll-view :scroll-y="true" style="height: 100%"> + <u-cell-group v-if="isChooseP"> + <u-cell v-for="(item, index) in citys" :title="item.label" :arrow="false" :index="index" + :key="index" @click="cityChange(index)"> + <template v-slot:right-icon> + <u-icon v-if="isChooseC && city === index" size="17" + name="checkbox-mark"></u-icon> + </template> + </u-cell> + </u-cell-group> + </scroll-view> + </view> + </view> + <view class="area-item"> + <view class="u-padding-10 u-bg-gray" style="height: 100%;"> + <scroll-view :scroll-y="true" style="height: 100%"> + <u-cell-group v-if="isChooseC"> + <u-cell v-for="(item, index) in areas" :title="item.label" :arrow="false" :index="index" + :key="index" @click="areaChange(index)"> + <template v-slot:right-icon> + <u-icon v-if="isChooseA && area === index" size="17" + name="checkbox-mark"></u-icon> + </template> + </u-cell> + </u-cell-group> + </scroll-view> + </view> + </view> + </view> + </view> + </u-popup> +</template> + +<script setup lang="ts"> +import { ref, computed, onMounted, PropType } from 'vue'; +import provincesSource from "./province.js"; +import citysSource from "./city.js"; +import areasSource from "./area.js"; + +// 瀹氫箟鎺ュ彛 +interface Region { + label: string; + value: string; +} + +interface CitySelectResult { + province: Region; + city: Region; + area: Region; +} + +interface TabItem { + name: string; +} + +// Props 瀹氫箟 +const props = defineProps({ + // 閫氳繃鍙屽悜缁戝畾鎺у埗缁勪欢鐨勫脊鍑轰笌鏀惰捣 + modelValue: { + type: Boolean, + default: false + }, + // 榛樿鏄剧ず鐨勫湴鍖猴紝鍙紶绫讳技["娌冲寳鐪�", "绉︾殗宀涘競", "鍖楁埓娌冲尯"] + defaultRegion: { + type: Array as PropType<string[]>, + default: () => [] + }, + // 榛樿鏄剧ず鍦板尯鐨勭紪鐮侊紝defaultRegion鍜宎reaCode鍚屾椂瀛樺湪锛宎reaCode浼樺厛锛屽彲浼犵被浼糩"13", "1303", "130304"] + areaCode: { + type: Array as PropType<string[]>, + default: () => [] + }, + // 鏄惁鍏佽閫氳繃鐐瑰嚮閬僵鍏抽棴Picker + maskCloseAble: { + type: Boolean, + default: true + }, + // 寮瑰嚭鐨剒-index鍊� + zIndex: { + type: [String, Number], + default: 0 + } +}); + +// 浜嬩欢瀹氫箟 +const emit = defineEmits<{ + (e: 'update:modelValue', value: boolean): void; + (e: 'close'): void; + (e: 'city-change', result: CitySelectResult): void; +}>(); + +const cityValue = ref(""); +const isChooseP = ref(false); // 鏄惁宸茬粡閫夋嫨浜嗙渷 +const province = ref(0); // 鐪佺骇涓嬫爣 +const provinces = ref<Region[]>(provincesSource); +const isChooseC = ref(false); // 鏄惁宸茬粡閫夋嫨浜嗗競 +const city = ref(0); // 甯傜骇涓嬫爣 +const citys = ref<Region[]>(citysSource[0]); +const isChooseA = ref(false); // 鏄惁宸茬粡閫夋嫨浜嗗尯 +const area = ref(0); // 鍖虹骇涓嬫爣 +const areas = ref<Region[]>(areasSource[0][0]); +const tabsIndex = ref(0); +const tabs = ref(); + +// 璁$畻灞炴�� +const isChange = computed(() => { + return tabsIndex.value > 1; +}); + +const genTabsList = computed((): TabItem[] => { + let tabsList: TabItem[] = [{ + name: "璇烽�夋嫨" + }]; + + if (isChooseP.value) { + tabsList[0].name = provinces.value[province.value].label; + tabsList[1] = { + name: "璇烽�夋嫨" + }; + } + + if (isChooseC.value) { + tabsList[1].name = citys.value[city.value].label; + tabsList[2] = { + name: "璇烽�夋嫨" + }; + } + + if (isChooseA.value) { + tabsList[2].name = areas.value[area.value].label; + } + + return tabsList; +}); + +const uZIndex = computed(() => { + // 濡傛灉鐢ㄦ埛鏈変紶閫抸-index鍊硷紝浼樺厛浣跨敤 + return props.zIndex ? props.zIndex : 1075; // 鍋囪$u.zIndex.popup涓�1075 +}); + +// 鏂规硶 +const setProvince = (label = "", value = "") => { + provinces.value.map((v, k) => { + if (value ? v.value == value : v.label == label) { + provinceChange(k); + } + }); +}; + +const setCity = (label = "", value = "") => { + citys.value.map((v, k) => { + if (value ? v.value == value : v.label == label) { + cityChange(k); + } + }); +}; + +const setArea = (label = "", value = "") => { + areas.value.map((v, k) => { + if (value ? v.value == value : v.label == label) { + isChooseA.value = true; + area.value = k; + } + }); +}; + +const close = () => { + emit('update:modelValue', false); + emit('close'); +}; + +const tabsChange = (value: { index: number }) => { + tabsIndex.value = value.index; +}; + +const provinceChange = (index: number) => { + isChooseP.value = true; + isChooseC.value = false; + isChooseA.value = false; + province.value = index; + citys.value = citysSource[index]; + tabsIndex.value = 1; +}; + +const cityChange = (index: number) => { + isChooseC.value = true; + isChooseA.value = false; + city.value = index; + areas.value = areasSource[province.value][index]; + tabsIndex.value = 2; +}; + +const areaChange = (index: number) => { + isChooseA.value = true; + area.value = index; + const result: CitySelectResult = { + province: provinces.value[province.value], + city: citys.value[city.value], + area: areas.value[area.value] + }; + emit('city-change', result); + close(); +}; + +// 鐢熷懡鍛ㄦ湡閽╁瓙 +onMounted(() => { + if (props.areaCode.length == 3) { + setProvince("", props.areaCode[0]); + setCity("", props.areaCode[1]); + setArea("", props.areaCode[2]); + } else if (props.defaultRegion.length == 3) { + setProvince(props.defaultRegion[0], ""); + setCity(props.defaultRegion[1], ""); + setArea(props.defaultRegion[2], ""); + } +}); +</script> + +<style lang="scss"> +.area-box { + width: 100%; + overflow: hidden; + height: 800rpx; + + >view { + width: 150%; + transition: transform 0.3s ease-in-out 0s; + transform: translateX(0); + + &.change { + transform: translateX(-33.3333333%); + } + } + + .area-item { + width: 33.3333333%; + height: 800rpx; + } +} +</style> \ No newline at end of file -- Gitblit v1.9.3