一、页面概述
本项目实现了一个美观、实用的通讯录页面,采用 React 框架,结合 Ant Design 组件库与 TailwindCSS 原子化样式,支持按字母分组展示联系人,并提供便捷的字母索引导航。页面设计现代,交互流畅,适用于各类需要联系人管理的 Web 应用。
二、功能特点
- 字母分组展示
联系人自动按姓名首字母分组,分组标题悬浮吸顶,便于快速定位。 - 字母索引导航
右侧集成 Ant Design Anchor 组件,点击字母可平滑滚动至对应分组,提升查找效率。 - 响应式布局
页面采用 Flex 布局与 TailwindCSS,适配不同屏幕尺寸,移动端与桌面端均有良好体验。 - 美观的 UI 设计
联系人卡片采用圆角、阴影、渐变背景等设计,整体风格简洁现代,支持主题色自定义。 - 交互细节优化
支持悬浮高亮、点击反馈、分组吸顶等细节,提升用户操作的愉悦感。
三、技术亮点
- React 组件化开发
代码结构清晰,易于维护和扩展,支持数据动态加载与状态管理。 - Ant Design Anchor 组件深度定制
通过自定义样式和参数,完美融合 Antd Anchor 字母索引与自定义通讯录列表。 - TailwindCSS 原子化样式
快速开发高质量 UI,无需编写繁琐的 CSS,极大提升开发效率。 - 平滑滚动与吸顶效果
利用原生 scroll-behavior 和 CSS sticky,实现分组标题吸顶与平滑滚动,用户体验极佳。 - 高可扩展性
支持后续集成搜索、分组管理、联系人详情等功能,适合二次开发。
四、适用场景
- 企业/组织内部通讯录管理系统
- 社交类 App/Web 的联系人模块
- 教育、医疗、政务等行业的人员名录展示
- 需要字母索引导航的任意列表型数据页面
- 需要快速查找、分组展示的用户信息管理后台
五、全部源码
import { useRef } from "react";
import { Anchor } from "antd";
import "antd/dist/reset.css";
// 示例数据
const contacts = [
{ name: "Alice", initial: "A" },
{ name: "Aaron", initial: "A" },
{ name: "Bob", initial: "B" },
{ name: "Bella", initial: "B" },
{ name: "Cindy", initial: "C" },
{ name: "David", initial: "D" },
{ name: "Eve", initial: "E" },
{ name: "Frank", initial: "F" },
{ name: "Grace", initial: "G" },
{ name: "Helen", initial: "H" },
{ name: "Ivy", initial: "I" },
{ name: "Jack", initial: "J" },
{ name: "Kathy", initial: "K" },
{ name: "Leo", initial: "L" },
{ name: "Mona", initial: "M" },
{ name: "Nina", initial: "N" },
{ name: "Oscar", initial: "O" },
{ name: "Paul", initial: "P" },
{ name: "Queen", initial: "Q" },
{ name: "Rose", initial: "R" },
{ name: "Sam", initial: "S" },
{ name: "Tom", initial: "T" },
{ name: "Uma", initial: "U" },
{ name: "Vera", initial: "V" },
{ name: "Will", initial: "W" },
{ name: "Xander", initial: "X" },
{ name: "Yuki", initial: "Y" },
{ name: "Zack", initial: "Z" },
];
// 分组
const grouped = contacts.reduce((acc, cur) => {
acc[cur.initial] = acc[cur.initial] || [];
acc[cur.initial].push(cur);
return acc;
}, {});
const letters = Array.from({ length: 26 }, (_, i) =>
String.fromCharCode(65 + i)
);
export default function ContactsAntd() {
const listRef = useRef();
// 生成Anchor的items
const anchorItems = letters
.filter((letter) => grouped[letter])
.map((letter) => ({
key: letter,
href: `#${letter}`,
title: letter,
}));
return (
<>
{/* 覆盖Antd Anchor字母索引栏padding-inline的全局样式 */}
<style>{`
:where(.css-dev-only-do-not-override-1rfzxih).ant-anchor-wrapper .ant-anchor .ant-anchor-link {
padding-inline: 8px 0 !important;
line-height: 14px;
}
:where(.css-dev-only-do-not-override-1rfzxih).ant-anchor-wrapper:not(.ant-anchor-wrapper-horizontal) .ant-anchor::before {
border-inline-start: 2px solid rgb(239, 68, 68);
}
:where(.css-dev-only-do-not-override-1rfzxih).ant-anchor-wrapper .ant-anchor .ant-anchor-link-active>.ant-anchor-link-title {
font-weight: bold;
}
`}</style>
<div className="flex relative h-screen bg-gradient-to-br from-rose-100 to-white">
{/* 通讯录列表 */}
<div
ref={listRef}
className="flex-1 overflow-y-auto px-4 py-4"
style={{ scrollBehavior: "smooth" }}
>
<h1 className="text-2xl font-bold mb-4 text-red-700 tracking-wide">
通讯录
</h1>
{letters.map(
(letter) =>
grouped[letter] && (
<div key={letter} id={letter}>
<div className="sticky top-0 z-10 text-red-600 font-bold px-2 py-1 rounded mt-2 mb-1 shadow-sm backdrop-blur bg-white/90">
{letter}
</div>
<div className="space-y-2 mb-4">
{grouped[letter].map((c) => (
<div
key={c.name}
className="flex items-center gap-3 px-4 py-2 bg-white rounded-xl shadow hover:bg-rose-50 transition cursor-pointer group border border-rose-100 hover:border-red-300"
>
<div
className={`w-10 h-10 flex items-center justify-center rounded-full text-white text-lg font-bold shadow bg-red-500 group-hover:bg-red-600`}
>
{c.name[0]}
</div>
<span className="text-gray-800 text-base font-medium group-hover:text-red-700 transition">
{c.name}
</span>
</div>
))}
</div>
</div>
)
)}
</div>
{/* 右侧字母索引栏(Antd Anchor) */}
<div className="fixed right-1 top-1/2 -translate-y-1/2 z-20 flex flex-col items-center justify-center border-2 border-red-500 rounded-sm py-0 pr-1 bg-white border-l-0">
<Anchor
direction="vertical"
items={anchorItems}
getContainer={() => listRef.current}
affix={false}
showInkInFixed={true}
style={{ background: "transparent" }}
/>
</div>
</div>
</>
);
}
注意
Anchor 锚点实现,如果通讯录组件使用在弹框组件内,点击锚点时,滚动条会出现异常,需要使用 getContainer
属性,指定锚点滚动容器,否则会默认滚动到页面顶部。
react+antd Anchor(锚点组件)通讯录字母索引实现 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿动态资讯