You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按姓名首字母排序并分组渲染联系人列表

按姓名首字母分组实现通讯录效果

直接按以下两步处理即可,代码可直接复用:

  • 第一步:先对原始联系人数据做排序、分组处理,输出结构化的分组数据
  • 第二步:遍历分组数据,依次渲染字母标题和对应分组下的联系人条目

数据处理逻辑

以下工具函数可以直接把你提供的原始数组转换为按首字母排序、分组的结构,已经兼容字段为空的边界场景:

// 原始联系人数据
export const rows = [
  {
    id: 1,
    name: 'Snow',
    email: 'Jon',
    contact: 35,
    avatar: ''
  },
  { id: 2, name: 'Lannister', email: 'Cersei', contact: 42, avatar: '' },
  { id: 3, name: 'Lannister', email: 'Jaime', contact: 45, avatar: '' },
  { id: 4, name: 'Stark', email: 'Arya', contact: 16, avatar: '' },
  { id: 5, name: 'Targaryen', email: 'Daenerys', contact: null, avatar: '' },
  { id: 6, name: 'Melisandre', email: null, contact: 150, avatar: '' },
  { id: 7, name: 'Clifford', email: 'Ferrara', contact: 44, avatar: '' },
  { id: 8, name: 'Frances', email: 'Rossini', contact: 36, avatar: '' },
  { id: 9, name: 'Roxie', email: 'Harvey', contact: 65, avatar: '' },
  { id: 11, name: 'Snow', email: 'Jon', contact: 35 , avatar: ''},
  { id: 12, name: 'Lannister', email: 'Cersei', contact: 42, avatar: '' },
];

/**
 * 联系人按姓名首字母排序分组
 * @param {Array} contactList 原始联系人列表
 * @returns {Array} 分组后结构:[{ letter: '首字母', list: [对应联系人数组] }]
 */
function groupContactsByFirstLetter(contactList) {
  // 过滤name为空的无效数据,剩余数据按姓名字母顺序升序排列
  const sortedList = contactList
    .filter(item => item?.name)
    .sort((a, b) => a.name.localeCompare(b.name));

  const groupMap = new Map();
  // 遍历排序后的数据,按首字母归组
  sortedList.forEach(contact => {
    const firstLetter = contact.name.charAt(0).toUpperCase();
    if (!groupMap.has(firstLetter)) {
      groupMap.set(firstLetter, []);
    }
    groupMap.get(firstLetter).push(contact);
  });

  // 分组本身也按字母顺序排序,转换为方便渲染的数组结构
  return Array.from(groupMap.entries())
    .sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
    .map(([letter, list]) => ({ letter, list }));
}

// 调用即可得到最终用于渲染的分组数据
const groupedContacts = groupContactsByFirstLetter(rows);

处理后你会得到如下结构的数据,和通讯录需要的渲染结构完全匹配:

[
  { letter: 'C', list: [/* Clifford 联系人项 */] },
  { letter: 'F', list: [/* Frances 联系人项 */] },
  { letter: 'L', list: [/* 3个Lannister 联系人项 */] },
  { letter: 'M', list: [/* Melisandre 联系人项 */] },
  { letter: 'R', list: [/* Roxie 联系人项 */] },
  { letter: 'S', list: [/* Snow、Stark 共3个联系人项 */] },
  { letter: 'T', list: [/* Targaryen 联系人项 */] },
]

页面渲染参考

不管使用原生JS、Vue还是React,只要双层遍历上述分组数据即可,以React为例的简单渲染代码如下:

function ContactBook() {
  return (
    <div className="contact-container">
      {groupedContacts.map(group => (
        <div key={group.letter} className="contact-group">
          {/* 字母分类标题,可加样式做成常见的吸顶效果 */}
          <div className="group-letter-title">{group.letter}</div>
          {/* 渲染当前分组下所有联系人 */}
          {group.list.map(contact => (
            <div key={contact.id} className="contact-item">
              <div className="contact-avatar">
                {contact.avatar ? <img src={contact.avatar} alt="" /> : contact.name.charAt(0)}
              </div>
              <div className="contact-meta">
                <div className="contact-name">{contact.name}</div>
                <div className="contact-subtext">{contact.email ?? '未填写邮箱'}</div>
              </div>
            </div>
          ))}
        </div>
      ))}
    </div>
  )
}

补充说明

  • 排序使用localeCompare实现,相比直接对比字符编码,可正确兼容带特殊字符、非英文姓名的排序场景
  • 已经默认处理了name、email、contact字段为null的边界情况,不会出现运行报错
  • 如果需要实现侧边字母快速导航,直接提取所有分组的letter字段生成导航项即可,点击后滚动到对应分组位置就能实现完整的通讯录交互

内容的提问来源于stack exchange,提问作者Viet Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:01:26