| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 | <template>  <view class="city-picker-container">    <view class="picker-content">      <view class="header">        <text class="title">城市地区</text>      </view>      <view class="hot-cities-section">        <view class="sub-title">热门城市</view>        <view class="hot-cities-grid">          <view            class="hot-city-item"            v-for="city in hotCities"            :key="city"            @click="handleHotCityClick(city)"          >            {{ city }}          </view>        </view>      </view>      <view class="divider"></view>      <!-- 选择器 -->      <view class="picker-wrapper">        <view class="picker-header">          <text>省份</text>          <text>城市</text>          <text>区县</text>        </view>        <picker-view :value="pickerValue" @change="handlePickerChange" class="picker-view">          <!-- 省份列 -->          <picker-view-column>            <view              class="picker-item"              :class="{ 'selected-item': pickerValue[0] === index }"              v-for="(province, index) in provinces"              :key="province.name"            >              {{ province.name }}            </view>          </picker-view-column>          <!-- 城市列 -->          <picker-view-column>            <view              class="picker-item"              :class="{ 'selected-item': pickerValue[1] === index }"              v-for="(city, index) in cities"              :key="city.name"            >              {{ city.name }}            </view>          </picker-view-column>          <!-- 区县列 -->          <picker-view-column>            <view              class="picker-item"              :class="{ 'selected-item': pickerValue[2] === index }"              v-for="(area, index) in areas"              :key="area.name"            >              {{ area.name }}            </view>          </picker-view-column>        </picker-view>      </view>      <!-- 确认按钮 -->      <view class="footer">        <button class="confirm-btn" @click="handleConfirm">确定</button>      </view>    </view>  </view></template><script setup>import { ref, watch, computed } from 'vue';import { cityData, hotCities } from './city-data.js';const emit = defineEmits(['update:show', 'confirm']);// --- Data ---const provinces = ref(cityData);const cities = ref([]);const areas = ref([]);const pickerValue = ref([0, 0, 0]);const selectedProvince = computed(() => provinces.value[pickerValue.value[0]] || {});const selectedCity = computed(() => cities.value[pickerValue.value[1]] || {});const selectedArea = computed(() => areas.value[pickerValue.value[2]] || {});// 确认选择const handleConfirm = () => {  const result = {    province: selectedProvince.value.name,    city: selectedCity.value.name,    area: selectedArea.value.name,  };  emit('confirm', result);};// picker-view 滚动时触发const handlePickerChange = (e) => {  const newPickerValue = e.detail.value;  const [provinceIndex, cityIndex, areaIndex] = newPickerValue;  const oldProvinceIndex = pickerValue.value[0];  const oldCityIndex = pickerValue.value[1];  // 如果省份改变了  if (provinceIndex !== oldProvinceIndex) {    // 更新城市列表和地区列表,并将它们的索引重置为0    cities.value = provinces.value[provinceIndex].children;    areas.value = cities.value[0]?.children || [];    pickerValue.value = [provinceIndex, 0, 0];  }   // 如果城市改变了  else if (cityIndex !== oldCityIndex) {    // 更新地区列表,并将地区索引重置为0    areas.value = cities.value[cityIndex]?.children || [];    pickerValue.value = [provinceIndex, cityIndex, 0];  }   // 如果只是地区改变  else {    pickerValue.value = newPickerValue;  }};// 点击热门城市// 新方法:遍历cityData找到对应的省市区并更新pickerValueconst handleHotCityClick = (cityName) => {  let provinceIndex = -1;  let cityIndex = -1;  let found = false;  // 遍历省份  for (let i = 0; i < provinces.value.length; i++) {    const province = provinces.value[i];    // 遍历城市    if (province.children && province.children.length > 0) {      for (let j = 0; j < province.children.length; j++) {        const city = province.children[j];        // 检查城市名是否匹配(使用 startsWith 来兼容 "杭州" 和 "杭州市")        if (city.name.startsWith(cityName)) {          provinceIndex = i;          cityIndex = j;          found = true;          break; // 找到城市,跳出内层循环        }      }    }    if (found) {      break; // 找到城市,跳出外层循环    }  }  // 如果找到了对应的城市  if (found) {    // 1. 更新城市列表,使其为选中省份的城市列表    cities.value = provinces.value[provinceIndex].children;        // 2. 更新区县列表,使其为选中城市的区县列表    //    使用可选链 ?. 防止选中城市没有区县数据(如海南省直辖县)    areas.value = cities.value[cityIndex]?.children || [];        // 3. 更新 pickerValue,这会驱动 picker-view 滚动到指定位置    //    区县默认选择第一个 (索引为0)    pickerValue.value = [provinceIndex, cityIndex, 0];  } else {    // 如果在数据中找不到该热门城市,可以给一个提示    uni.showToast({      title: `未在数据源中找到 ${cityName}`,      icon: 'none'    });  }};// 初始化数据const initialize = () => {  const [pIndex, cIndex] = pickerValue.value;  cities.value = provinces.value[pIndex]?.children || [];  areas.value = cities.value[cIndex]?.children || [];};// 初始化initialize();defineExpose({	initialize})</script><style lang="scss" scoped>.city-picker-container {  .picker-content {    width: 100%;    background-color: #ffffff;    border-radius: 0 0 24rpx 24rpx;    display: flex;    flex-direction: column;  }}.header {  padding: 36rpx 0 0 28rpx;  position: relative;  .title {    font-family: PingFang-SC, PingFang-SC;    font-weight: bold;    font-size: 36rpx;    color: #252525;    line-height: 36rpx;  }}.hot-cities-section {  padding: 0 28rpx;  margin-top: 40rpx;  .sub-title {    font-family: PingFangSC, PingFang SC;    font-weight: 400;    font-size: 24rpx;    color: #989998;    line-height: 24rpx;  }  .hot-cities-grid {    display: grid;    grid-template-columns: repeat(4, 1fr);    gap: 20rpx;	margin: 24rpx 0;  }  .hot-city-item {    border-radius: 6rpx;    border: 1rpx solid #E5E7EB;    padding: 13rpx 0;    font-family: PingFangSC, PingFang SC;    font-weight: 400;    font-size: 24rpx;    color: #252525;    line-height: 33rpx;    text-align: center;  }}.divider {  height: 14rpx;  background: #F7F7F7;}.picker-wrapper {  .picker-header {    display: flex;    justify-content: space-around;    padding: 20rpx 0;    font-family: PingFang-SC, PingFang-SC;    font-weight: bold;    font-size: 28rpx;    color: #252525;    line-height: 36rpx;  }}.picker-view {  width: 100%;  height: 380rpx;}.picker-item {  display: flex;  align-items: center;  justify-content: center;  font-size: 30rpx;  color: #A4A4A4;  transition: all 0.2s;    &.selected-item {    font-size: 32rpx;    color: #252525;  }}.footer {  padding: 64rpx 147rpx 40rpx;  .confirm-btn {    width: 100%;    height: 80rpx;    line-height: 88rpx;    background: #B7F358;    border-radius: 45rpx;    font-family: PingFang-SC, PingFang-SC;    font-weight: bold;    font-size: 28rpx;    color: #252525;    line-height: 80rpx;	letter-spacing: 2rpx;    border: none;    &:after {      border: none;    }  }}</style>
 |