vue 仿微信通讯录实现侧边字母快速检索

  • Post author:
  • Post category:vue


预览图

实现步骤

  1. 处理后台传来的数据,数据格式化

     pySegSort(arr){
            if (!String.prototype.localeCompare) return null
            // let letters = 'abcdefghjklmnopqrstwxyz'.split('')
            let letters = 'ABCDEFGHJKLMNOPQRSTWXYZ'.split('')
            let zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split('')
            let segs = []
            letters.forEach((item, i) => {
                let cur = { letter: item, data: [] }
                arr.forEach((item) => {
                    if(item.city.localeCompare(zh[i])>=0&&item.city.localeCompare(zh[i+1])<0){
                        cur.data.push(item)
                    }         
                })
                if (cur.data.length) {   
                        cur.data.sort(function(a, b) {
                            return a.city.localeCompare(b, 'zh')
                        })
                        segs.push(cur)
                    }
            })

            return segs
        },

将数据格式化为以下格式

[
{
    title:'A'
    data:[
        {
            city:'安康市‘,
            id:1
            }
        ]
    },
{
    title:'B'
    data:[
        {
            city:'北京市‘,
            id:2
            }
        ]
    },
    ]
  1. 利用

    Element.scrollTo()

做滑动效果,需要计算出每个字母标题下数组的长度,计算结果放入一个数组中

 calculateTotalHeight() {
            var list = this.$refs.listGroup
            var height = 0
            this.listHeight.push(height)
            console.log(list.length,'list')
            if(list&&list.length>0){
                for (var i = 0; i < list.length; i++) {
                    var item = list[i]
                    height += item.clientHeight
                    this.listHeight.push(height)
                }
            }
        }
  1. 点击侧边字母滑动到对应字母标题

        goIndex(params) {
            const groupRef = this.$refs.groupRef
            const titleRef = this.$refs.titleRef
            titleRef.map((item,index) => {
            if (item.innerText === params) {
                groupRef.scrollTo(0,this.listHeight[index])
            }
            })
        },

html部分

   <div class="content">
            <div class="top">
                <div style="height: 50%;margin:0 0.4rem">
                    <h5>常用大区</h5>
                    <div class="one">
                        <van-tag class="tagsClass" v-for="(area,index) in regionList" :key="index" @click="chooseArea(area)">{{area.regionName}}</van-tag>
                    </div>
                </div>
                <div style="height: 50%;margin:0 0.4rem">
                    <h5>常用城市</h5>
                    <div class="one">
                        <van-tag class="tagsClass" v-for="(city,index) in  cityList" :key="index" @click="chooseCities(city)">{{city.city}}</van-tag>
                    </div>
                </div>
            </div>
            <div class="bottom" ref="groupRef">
                <ul class="list-shortcut">
                    <li  @click="goIndex(item)" v-for="(item,index) in shortcut" :key="index">{{item}}</li>
                </ul>
                <van-list
                v-model="loading"
                :finished="finished"
                finished-text="没有更多了"
                @load="onLoad"
                
                >   
                    <ul >
                        <li  v-for="(item,index)  in allList" 
                        class="list-group" 
                        :key="index"
                        ref="listGroup"
                       >
                            <h4 class="list-group-title" ref="titleRef">{{ item.letter }}</h4>
                            <ul>
                                <li v-for="city in item.data" @click="chooseCity(city)"  class="listitem" :key="city.id">
                                    <span>{{city.city}}</span><span>{{city.regionName}}</span>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </van-list>
            </div>
        </div>

就完成啦!!

完整代码如下:

<template>
    <div class="RegionSelect">
        <div class="header">
            <!-- 标题栏 -->
            <i slot="left" class="iconfont icon-31fanhui1" style="margin: 0.5rem;" @click="$router.go(-1)"/>
            <input class="inputClass" id="inut" placeholder="输入城市名进行搜索" @click="searchCity"></input>
            <button class="buttonClass" @click="searchCity"><i class="el-icon-search"></i></button>
            <div class="areaClass"> 
                <i class="el-icon-location-outline iconClass" ></i>
                <span style="font-size: 0.6rem;margin-left:0.2rem;" v-if="city">当前定位城市 {{area}} · {{city}} </span>
                <span style="font-size: 0.6rem;margin-left:0.2rem;" v-else>当前定位城市 {{area}} </span>
            </div>
        </div>
        <div class="content">
            <div class="top">
                <div style="height: 50%;margin:0 0.4rem">
                    <h5>常用大区</h5>
                    <div class="one">
                        <van-tag class="tagsClass" v-for="(area,index) in regionList" :key="index" @click="chooseArea(area)">{{area.regionName}}</van-tag>
                    </div>
                </div>
                <div style="height: 50%;margin:0 0.4rem">
                    <h5>常用城市</h5>
                    <div class="one">
                        <van-tag class="tagsClass" v-for="(city,index) in  cityList" :key="index" @click="chooseCities(city)">{{city.city}}</van-tag>
                    </div>
                </div>
            </div>
            <div class="bottom" ref="groupRef">
                <ul class="list-shortcut">
                    <li  @click="goIndex(item)" v-for="(item,index) in shortcut" :key="index">{{item}}</li>
                </ul>
                <van-list
                v-model="loading"
                :finished="finished"
                finished-text="没有更多了"
                @load="onLoad"
                
                >   
                    <ul >
                        <li  v-for="(item,index)  in allList" 
                        class="list-group" 
                        :key="index"
                        ref="listGroup"
                       >
                            <h4 class="list-group-title" ref="titleRef">{{ item.letter }}</h4>
                            <ul>
                                <li v-for="city in item.data" @click="chooseCity(city)"  class="listitem" :key="city.id">
                                    <span>{{city.city}}</span><span>{{city.regionName}}</span>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </van-list>
            </div>
        </div>
    </div>
</template>
  
<script>
  import defaultImg from "mixins/defaultImg";
  
  import { mapGetters, mapActions } from "vuex";
  import {getRegionCityLog,regionCityList,chooseCity } from "service/getData";
  //   import { Tab, TabItem, Divider } from "vux";
  import {Tab,Tag,Tabs, List, Icon} from 'vant';
  
  import { Loadmore } from "mint-ui";
  import NewMHeader from 'components/header/MHeader.vue'
  import SortBar from "components/item/SortBar.vue";
  import SearchHeadRes from "components/search/SearchHeadResult.vue";
  import NoResult from "components/search/NoResult.vue";

  export default {
    name: "RegionSelect",
    components: {
        NewMHeader,
        [Tab.name]: Tab,
        [Tabs.name]: Tabs,
        [List.name]: List,
        [Icon.name]: Icon,
        [Tag.name]:Tag
    },
    data() {
      return {
        isTouch:false,
        touch:{},
        allList:[],
        initData:[],
        loading: false,
        finished: false,
        cityList:[],
        regionList:[],    
        listHeight: [],
        areaList:[],
        shortcut:[ 'A',
            'B',
            'C',
            'D',
            'E',
            'F',
            'G',
            'H',
            'I',
            'J',
            'K',
            'L',
            'M',
            'N',
            'O',
            'P',
            'Q',
            'R',
            'S',
            'T',
            'U',
            'V',
            'W',
            'X',
            'Y',
            'Z'],
        area:'内蒙古大区',
        city:'呼和浩特',
      };
    },
    computed: {
        ...mapGetters([
        'regionInfo', //默认大区
        ]),
  },
    methods: {
        ...mapActions([
        'getRegionInfo', //通过默认地址查询大区
        'getRegionInfos', //通过默认地址查询大区
        ]),
        // 处理地区数据
        pySegSort(arr){
            if (!String.prototype.localeCompare) return null
            // let letters = 'abcdefghjklmnopqrstwxyz'.split('')
            let letters = 'ABCDEFGHJKLMNOPQRSTWXYZ'.split('')
            let zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split('')
            let segs = []
            letters.forEach((item, i) => {
                let cur = { letter: item, data: [] }
                arr.forEach((item) => {
                    if(item.city.localeCompare(zh[i])>=0&&item.city.localeCompare(zh[i+1])<0){
                        cur.data.push(item)
                    }         
                })
                if (cur.data.length) {   
                        cur.data.sort(function(a, b) {
                            return a.city.localeCompare(b, 'zh')
                        })
                        segs.push(cur)
                    }
            })

            return segs
        },
        // 获取常用城市和大区
        async getRegionLog(){
            this.area = this.regionInfo[0].regionName
            this.city = this.regionInfo[0].city
            let list = await regionCityList()
            if(list.code == 101){
                this.initData = list.data
                let lists = await this.pySegSort(list.data) 
                this.allList = lists
            }
            let res =  await getRegionCityLog({
                regionCount:8,
                cityCount:10
            })
            if(res.code == 101){
                this.cityList = res.data.cityList
                this.regionList = res.data.regionList
            }
        },
        async onLoad() {
          
      },
      // 选择城市
      async chooseCity(item){
            await chooseCity({
                id: item.id,
            }).then(res => {
                if (res.code == 101) {
                    this.area = item.regionName
                    this.city = item.city
                    this.getRegionInfo({province:item.province,city:item.city}) // 修改默认地区\
                    this.$router.go(-1)
                    console.log(regionInfo,'regionInfo')
                }
            }).catch(() => {

            });
        },
        //快捷选择大区
        async chooseArea(area){
            await chooseCity({
                id: area.regionId,
            }).then(res => {
                if (res.code == 101) {
                    this.area = area.regionName
                    this.city = ""
                    // this.$store.commit('getRegionInfos',{regionName:area.regionName,regionId:area.regionId})
                    this.getRegionInfos({regionName:area.regionName,regionId:area.regionId}) // 修改默认地区
                    this.$router.go(-1)
                }
            }).catch(() => {

            });
        },
        // 快捷选择城市
        async chooseCities(city){
            var citydata = ''
            this.initData.forEach(element => {
                if(element.city == city.city){
                    citydata = element
                }
            });
            await chooseCity({
                id: citydata.id,
            }).then(res => {
                if (res.code == 101) {
                    this.area = citydata.regionName
                    this.city = citydata.city
                    this.getRegionInfo({province:citydata.province,city:citydata.city}) // 修改默认地区
                    this.$router.go(-1)
                }
            }).catch(() => {

            });
        },
        // 查找城市
        async searchCity(){
           this.$router.push('/RegionSearch')
        },
        goIndex(params) {
            const groupRef = this.$refs.groupRef
            const titleRef = this.$refs.titleRef
            titleRef.map((item,index) => {
            if (item.innerText === params) {
                groupRef.scrollTo(0,this.listHeight[index])
            }
            })
        },
        calculateTotalHeight() {
            var list = this.$refs.listGroup
            var height = 0
            this.listHeight.push(height)
            console.log(list.length,'list')
            if(list&&list.length>0){
                for (var i = 0; i < list.length; i++) {
                    var item = list[i]
                    height += item.clientHeight
                    this.listHeight.push(height)
                }
            }
        }
    },
    watch: {
        // $route(to, from) {
        //     window.location.reload(); //监测到路由发生跳转时刷新一次页面
        // },
    },
    mounted() {
        this.getRegionLog()
        setTimeout(()=>{
            this.calculateTotalHeight()
        }, 2000)
    },
    destroyed() {

    },
  };
</script>
<style lang="less" scoped="scoped">
.RegionSelect{
    background-color: #fff;
    padding: 0.2rem;
    height: 100%;
    .header{
        height: 6%;
        .inputClass{
            background-color: #f1f8fff9;
            position: relative;
            z-index: 9999;
            height: 1.4rem;
            width: 80%;
            text-indent: 0.8rem;
            border: none;
            border-radius: 1.4rem;
            margin-top: 0.25rem;
            margin-left:0.58rem;
        }
        .buttonClass{
            position: absolute;
            color: #ffffff;
            font-size: 0.8rem;
            top:0.26rem;
            right: 0.8rem;
            height: 1.3rem;
            width: 1.8rem;
            border: none;
            border-radius: 1.3rem;
            background-color:#dcdcdc ;
            z-index: 99999;
        }
        .iconClass{
            font-size: 0.7rem;
            margin-left: 0.4rem;
        }
        .areaClass{
            display: flex;
            align-items: center;
            margin-top: 0.6rem;
            color:#293F66;
            margin-bottom:0.2rem;
            font-weight: 500;
        }
    }
  .content{
    margin-top: 2rem;
    height: 84%;
    .top{
       height: 35%;
       margin-left: 0.6rem;
       .one{
         display: flex;
         flex-wrap: wrap;
         justify-content: flex-start;
        .tagsClass{
          background-color: #f1f8fff9 !important;
          color: #293F66;
          padding:0.2rem 0.5rem;
          font-size:0.4rem;
          margin-right: 0.5rem;
          margin-top: 0.5rem;
        }
       }
    }
    .bottom{
       height: 65%;
       margin: 1rem 0.6rem;
       overflow-x: hidden;
       overflow-y: auto;
       .listitem{
          font-size: 0.4rem;
          padding: 0.4rem;
          margin-right: 0.2rem;
          border-bottom: solid 0.02rem rgb(219, 219, 219);
          display: flex;
          justify-content:space-between;
       }
       .listitem:hover{
          background-color:#f1f8fff9;
       }
       .list-shortcut{
            position: absolute;
            z-index: 99999;
            right: 0.4rem;
            bottom: 10rem;
            display: flex;
            flex-direction: column;
            justify-content: space-around;
            height: 10rem;
            font-size: 0.4rem;
            font-family: $font;
            font-weight: 400;
            color: #979797;
            li {
                text-align: center;
                cursor: pointer;
            }
            li:hover{
                height: 0.8rem;
                width: 0.6rem;
                border-radius: 0.8rem;
                font-size: 0.6rem;
                background-color: #f1f8fff9;
            }
       }
    }
  }
}
</style>
  



版权声明:本文为weixin_43525759原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。