vue3+ TS pinyin uniapp 索引列表-(A-Z)按首字母排序 ,锚点定位
获取一维数组 地址列表
<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>