vue3+ TS pinyin uniapp 索引列表-(A-Z)按首字母排序 ,锚点定位

发布时间 2023-06-09 10:40:51作者: 假装学习

获取一维数组 地址列表

<script lang="ts" setup>
import { getLocationList } from "@/apis/activity";
import {onLoad} from "@dcloudio/uni-app";
import { pinyin } from "pinyin-pro"
import {ref} from "vue";

const systemInfo = uni.getSystemInfoSync()
const cityArr = ref<any>({})
// 扁平城市列表
const flatCityArr = ref<any>([])

const scrollCityName = ref("");

const searchFlag = ref(false)
// 搜索结果
const searchList = ref<any>([])

const textlist= ref(["北京","深圳","上海","广州","重庆","成都","杭州","郑州","武汉","南京","西安"])

/**
 * 获取城市地点
 */
const getCityArr = () => {
  getLocationList(1).then(e => {
    // const citys = e.map(item => item.locationName)
    const cityCon = e.flat(Infinity).map((item: any) => {
      return {name: item.locationName, id: item.id}
    })
      // [...citys, ...cityCon]
    const arr = cityCon;
    flatCityArr.value = arr;
    const dataObj: any = {}
    for (let i = 0; i < arr.length; i++) {
      let item = arr[i]
      let initial = pinyin(arr[i].name, {
        pattern: 'first',
        toneType: 'none'
      }).substr(0, 1).toLocaleUpperCase();
      if (!dataObj[initial]) {
        dataObj[initial] = []
      }
      dataObj[initial].push(item)
    }
    // 排序
    cityArr.value = Object.keys(dataObj)
      .sort()
      .reduce((acc: any, key) => {
        acc[key] = dataObj[key];
        return acc;
      }, {});
    console.log(cityArr.value)
  })
}

const handleInput = (value: string) => {
  if (value) {
    searchList.value = flatCityArr.value.filter((item: any) => item.name.indexOf(value) !== -1)
    searchFlag.value = true
  }
}

const handleExitSearch = () => {
  searchFlag.value = false;
  searchList.value = []
}

const scrollIntoCityLetter = (cityName: string) => {
  scrollCityName.value = cityName;
}

const selectAddress = (item: any) => {
  uni.navigateBack({delta: 1})
}

onLoad(() => {
  getCityArr()
})
</script>

页面  

<template>
  <view class="m-page">
    <m-navbar title="选择城市"/>
    <view class="m-content" :style="{height: `calc(100vh - ${systemInfo.statusBarHeight}px - 44px)`}">
      <view class="search">
        <u-search @clear="handleExitSearch" @change="handleInput" shape="square" bgColor="#fff"
                  :showAction="false"></u-search>
      </view>
      <view v-if="searchFlag" class="search-list">
        <view @tap="selectAddress(item)" class="search-item" v-for="(item, index) in searchList" :key="index">
          {{ item.name }}
        </view>
      </view>
      <view v-else class="index-list">
        <scroll-view class="city-list" scroll-y :scroll-into-view="scrollCityName">
          <view class="top">
            <view class="box">
              <view class="title">热门城市</view>
              <view class="city">
                <template v-for="(item, index) in textlist">
                            
                  <view class="item u-line-1" @tap="selectAddress(item)">
                    {{ item.name }}
                  </view>
                </template>
              </view>
            </view>
          </view>
          <view :id="item" class="initial" v-for="(item, index) in Object.keys(cityArr)" :key="index">
            <view class="letter">{{ item }}</view>
            <view @tap="selectAddress(cityItem)" class="city-item" v-for="(cityItem, cityIndex) in cityArr[item]"
                  :key="cityIndex">{{ cityItem.name }}
            </view>
          </view>
        </scroll-view>
        <view class="letter-box">
          <view @tap="scrollIntoCityLetter(item)" class="letter-box-item" v-for="(item, index) in Object.keys(cityArr)"
                :key="index">{{ item }}
          </view>
        </view>
      </view>
    </view>
  </view>
</template>
<style lang="scss" scoped>
.m-page {
  padding-bottom: 0;
  background: #fff;
}
.m-content {
  width: 100%;

  .top {
    width: 100%;
    background: #fff;
    .box {
      margin: 40rpx 0 30rpx 30rpx;

      .title {
        font-size: 26rpx;
        color: #A6ABB7;
      }

      .city {
        display: flex;
        flex-wrap: wrap;

        .item {
          margin-top: 24rpx;
          margin-right: 18rpx;
          text-align: center;
          width:26%;
          height: 80rpx;
          line-height: 80rpx;
          background: #FFFFFF;
          border-radius: 8rpx;
          border: 1rpx solid #E5E5E5;
          font-size: 30rpx;
          padding: 0 10rpx;
        }

        .add {
          display: flex;
          align-items: center;
          justify-content: center;

          uni-image {
            margin-right: 8rpx;
            width: 28rpx;
            height: 28rpx;
          }

          uni-text {
            max-width: 145rpx;
          }
        }
      }
    }
  }

  .index-list {
    width: 100%;
    height: calc(100% - 98rpx);
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .search-list {
    width: 100%;
    background: #fff;
    .search-item {
      width: calc(100% - 60rpx);
      margin: 0 30rpx;
      border-bottom: 1rpx solid #ededed;
      height: 88rpx;
      display: flex;
      justify-content: flex-start;
      align-items: center;
      color: #191a1b;
      font-size: 26rpx;
    }
  }

  .search {
    width: 100%;
    height: 98rpx;
    background: #f4f4f4;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 0 30rpx;
    box-sizing: border-box;
  }

  .city-list {
    width: calc(100% - 34rpx);
    height: 100%;

    .initial {
      width: 100%;
      .letter {
        width: 100%;
        height: 60rpx;
        color: #797d82;
        font-size: 24rpx;
        padding-left: 30rpx;
        box-sizing: border-box;
        display: flex;
        justify-content: flex-start;
        align-items: center;
        background: #f4f4f4;
      }
      .city-item {
        width: 100%;
        font-size: 28rpx;
        height: 96rpx;
        background: #fff;
        display: flex;
        justify-content: flex-start;
        align-items: center;
        padding-left: 30rpx;
        box-sizing: border-box;
      }
    }
  }
  .letter-box {
    width: 34rpx;
    background: #fff;
    .letter-box-item {
      width: 100%;
      height: 36rpx;
      color: #191a1b;
      font-size: 22rpx;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
}
</style>