小程序中利用字母索引条实现定位成员列表中的人员

225 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

背景

我们常会看见在大部分社交APP中都会存在通讯录列表、联系人列表、成员列表等类似的页面或功能,能够帮助我们更快的搜索或定位到我们想要交流、联系的人员。这种通讯录、联系人、成员管理等功能,通常以列表形式展现,并加以字母索引条来实现定位。本文今天将介绍如何实现成员管理列表中利用字母索引条来定位我们查询的人员。
本文实现效果功能图类似下方图示:

无标题-2021-05-02-1153.png

实现步骤

首先需要定义需要使用到的变量,主要包括存储所有成员的列表数组变量memberList、处理后的成员列表personList、不属于所有26个英文字母分组的成员列表unGroupList,字母索引数组letters

data: {
memberList: [],
personList: [],
unGrounpList: [],
letters: [],
}

然后在onLoad中调用接口获取所有成员数据,由于可能接口返回的数据不符合页面展示所用到数据的形式,需要对数据进行处理,处理函数为handleList():

handleList(){}

包括以下几类需要处理的情况:

  • 接口获取到的成员列表memberList数据为空时,重置personList并return
    if (this.data.memberList.length == 0) {
      this.setData({
        personList: []
      })
      return;
    }
  • 若成员列表数组中含有自己这一项,也需要排除掉
    let personList = [];
    let i = 0;
    // 调用外部js的方法ChineseToPinYin对数据进行分组
    let curObj = null;
    // 排除自身(我自己)
    let memberList = this.data.memberList.filter(item => !item.isSelf);
  • 由于需要通过字母索引条定位,索引需要将中文名字转为拼音,此时需要调用外部的js方法(pinyin.js文件暴露出的ChineseToPinYin()方法)实现中文转拼音,转为拼音之后截取首字母,赋值给sign属性,以便于按照sign进行分组,即按照26个英文字母实现将姓名拼音进行分组;
  • 存在该分组则直接将该成员姓名push进该分组的nickName
  • 不存在该分组,则新建该分组的对象,需要将该分组成员数据格式化为包括id、nickName和sign属性的对象,其中id可以唯一区分该分组成员,nickName为该分组下所有成员的名字数组、sign表示该分组成员对象是属于26个英文字母的哪个分组,比如,成员名字为“张潇洒”的成员,将该名字转为拼音为"zhangxiaosa",是以z为首字母开头的,所以其sign为"z",表示该成员属于"z"这一分组。
    personList.push({
      id: i,
      sign: pinyin.ChineseToPinYin(item.nickName).substr(0, 1),
      nickName: [item]
    })

成员按照姓名首字母分组的代码如下:

// 排除自身后对memberList循环处理
// 将处理后的数据存入personList中
memberList.forEach((item) => {
    let bool = personList.some(ite => {
       return ite.sign == pinyin.ChineseToPinYin(item.nickName).substr(0, 1)
    })
    if (personList.length == 0 || !bool) {
       personList.push({
         id: i,
         sign: pinyin.ChineseToPinYin(item.nickName).substr(0, 1),
         nickName: [item]
       })
       i++
     } else if (bool) {
        let a = pinyin.ChineseToPinYin(item.nickName).substr(0, 1)
          for (let s in personList) {
            if (a == personList[s].sign) {
              personList[s].nickName.push(item)
           }
         }
       }
     }
  })

  • 分好组后,使用排序方法将已经分好组的成员列表按照26个英文字母的先后顺序进行排序
    排序方法为:
  // 排序
  listSort(prop) {
    return function (a, b) {
      var value1 = a[prop].charCodeAt();
      var value2 = b[prop].charCodeAt();
      return value1 - value2
    }
  },

利用数组原生sort方法按照分组符号sign进行分组:

    // 利用sort方法进行排序
    personList.sort(this.listSort('sign'))
  • 对于所以不在26个英文字母分组下的人员,将他们保存到变量unGroupList中,并统一划分到"#"组,
// 不包含在26个英文字母分组下的人员,统一归到"#"组
    if (this.data.unGroupList.length != 0) {
      personList.push({
        id: 99,
        sign: '#',
        nickName: this.data.unRegister
      })
    }
  • 为每一分组统计所包含的总人数
    //为每一分组统计人数
    personList.forEach(item => {
      item.len = item.nickName.length
    });
    this.setData({
      personList,
    })
  • 初始化26个英文字母分组,以及"#"分组
    let pattern = new RegExp("[A-Z|#]")
    const letters = personList.filter(item => pattern.test(item.sign));
    this.setData({
      letters
    })
  • 由于需要实现点击字母滚动跳转到对应分组的位置,所以结合scroll-view组件的scroll-into-view属性绑定toView变量,并将当前分组符号sign传入去实现该功能
<scroll-view enable-back-to-top scroll-into-view="{{toView}}" scroll-y="true" scroll-top="{{sctop}}">
  <view wx:for="{{ personList }}" wx:for-item="item1" id="{{ 'inToView'+item1.id}}">
  ...
  </view>
</scroll-view>

<view class="letter" wx:for="{{letters}}" wx:key="index" catchtap="chooseLetter" data-item="{{item}}" data-index="{{index}}"> {{item.sign}}</view>
  clickLetter(e) {
    let currentItem = e.currentTarget.dataset.item;
    this.data.personList.forEach(item => {
      if (item.sign == currentItem.sign) {
        this.setData({
          toView: 'inToView' + currentItem.id //滚动条to指定view
        })
      }
    })
  },

上述方法通过设置toView为前缀'inToView'加上当前单击的字母索引,即可实现定位到以该字母为姓名拼音首字母的成员组别的位置。

总结

以上所有代码讲解了如何实现利用字母索引条定位查询组别人员的功能,主要是结合了scroll-view组件、中文转拼音函数、处理接口返回的成员数组函数、字母索引数组等相关方法和技术。