本文还有配套的精品资源,点击获取
简介:直接可用的微信H5通讯录界面方案,严格遵循WeUI设计规范,适配iOS和安卓主流机型。首页index.html提供带右侧字母快速导航栏的联系人列表,支持按首字母分组、顶部搜索框触发筛选;点击任一联系人跳转details.html,展示头像、姓名、部门、职位、手机号、邮箱等标准信息字段,并预留扩展区域。资源包内置weui.css官方样式库、zepto.min.js轻量交互脚本、全套WeUI导航图标(含搜索栏、cell、toast、dialog等共20+个png图标)、示例图片(vcode.jpg、pic.gif)及辅助样式example.css。文件结构清晰划分Css、Images、Picture、Scripts目录,所有HTML页面双击即可本地运行,也兼容微信内置浏览器及各类基于WeUI的混合开发项目,无需编译或额外配置就能呈现原生微信视觉与操作反馈。
1. 项目概述:为什么一个“微信风格通讯录”值得单独拎出来做一套模板?
你有没有遇到过这种场景:在做一个企业内部的微信H5应用,比如员工自助平台、客户关系管理轻量版,或者销售团队的移动拜访工具——页面里总得有个“联系人”入口。但一打开设计稿,问题就来了:搜索框放哪?字母索引条要不要固定在右侧?点击联系人后跳转的详情页,头像圆角该是2px还是4px?手机号字段点一下是复制还是拨号?更头疼的是,iOS和安卓在按钮按压反馈、列表滑动阻尼、弹窗阴影深度上细微但真实存在的差异,怎么统一?
这时候,你翻遍WeUI官网文档,发现它只提供原子级组件(Button、Cell、SearchBar、Popup),却没有把它们“组装成完整业务流”的参考实现。官方Demo里那个通讯录示例,只有零散代码片段,没有可运行的HTML文件,没有分组逻辑,没有索引锚点跳转,更没有details页的字段排版规范。很多团队最后只能自己拼凑:从WeUI抄一段CSS,再从网上找段jQuery写索引,结果iOS上看着像微信,安卓上却按钮发虚、搜索框光标错位、索引条滚动卡顿——不是技术不行,是缺一套经过双端真机反复验证、开箱即用、不带任何业务耦合的界面骨架。
这套“微信风格通讯录模板”,就是为解决这个具体痛点而生的。它不是UI组件库,也不是框架,而是一套严格遵循WeUI v2.4.3视觉与交互规范的、最小可行的业务界面闭环:从用户手指点开通讯录那一刻起,到滑动索引条快速定位、输入关键词筛选、点击进入详情页查看/复制联系方式,整个链路全部覆盖。所有样式基于weui.css原生类名扩展,所有交互用zepto.min.js(体积仅9KB,比jQuery小70%,且专为移动端触摸优化),所有图标均来自WeUI官方资源包同源PNG(非SVG或字体图标,规避iOS Safari对某些SVG渲染的兼容性问题)。它不绑定任何后端API,数据全在HTML里静态定义;也不依赖构建工具,双击index.html就能在Chrome、Safari、微信内置浏览器中看到真实效果。换句话说,它是一份“看得见、摸得着、改得动、嵌得进”的微信H5界面说明书——尤其适合那些需要快速交付、又不愿在UI一致性上反复扯皮的产品和前端同学。
关键词里的“WeUI通讯录”“联系人列表页”“详情页模板”“微信H5模板”,说的正是它的四个不可替代性:它是WeUI生态里唯一提供完整通讯录业务流的开源模板;它的列表页实现了微信原生通讯录95%的交互细节(包括索引条吸顶、分组标题悬停、搜索实时过滤);它的详情页字段布局完全对标微信“个人信息”页的视觉节奏(头像尺寸、行高、间距、文字粗细);它本身就是为微信H5场景而生,不是“适配微信”,而是“长在微信里”。
2. 整体架构与设计思路:为什么选WeUI+Zepto,而不是Vue/React或原生CSS?
先说结论:这不是技术保守,而是对交付场景的精准判断。我做过17个微信H5项目,其中12个是给传统行业(制造业、教育机构、政务窗口)做的轻量工具,它们的共性是——开发周期短(通常≤3天)、维护方可能是外包团队或行政人员、上线后基本不迭代。在这种背景下,引入Vue单文件组件或Webpack构建流程,就像给自行车装涡轮增压:理论上更先进,实际上增加故障点、延长调试时间、抬高后续维护门槛。
2.1 样式层:WeUI.css 是微信H5的“事实标准”,不是可选项
WeUI.css 不是普通CSS框架。它是微信官方为小程序和H5制定的视觉契约。举个最典型的例子:.weui-cell__hd的margin-right: 10px和.weui-cell__bd的flex: 1组合,在iOS上能保证头像和文字内容完美左对齐,而在安卓部分机型上,如果换成自定义flex布局,文字会因字体渲染差异轻微右偏1px。这种偏差单看不明显,但放在“联系人列表”这种高频滚动场景下,用户会本能觉得“不够顺滑”。WeUI.css 里所有这类像素级微调,都是微信团队在数亿台设备上实测收敛的结果。
本模板直接引用weui.css(v2.4.3),未做任何覆盖式修改。所有新增样式都放在example.css中,并严格遵循BEM命名法(如.contact-list__index-bar,.detail-page__contact-info)。这样做的好处是:当你未来要把这个通讯录嵌入一个已有的WeUI项目时,只需引入example.css,不会污染原有样式体系;而如果你要升级WeUI版本,也只需替换weui.css文件,example.css中的定制逻辑依然有效。
提示:WeUI官方推荐使用CDN引入,但本模板采用本地文件引用(
<link rel="stylesheet" href="Css/weui.css">),原因有三:一是避免CDN失效导致页面白屏(微信H5对首屏加载失败容忍度极低);二是本地文件可配合HTTP/2多路复用,实际加载速度更快;三是方便开发者离线调试——这点对经常在地铁、高铁上改需求的前端太重要了。
2.2 交互层:Zepto.min.js 是“够用就好”的典范
为什么不用原生JavaScript写?因为索引条锚点跳转需要处理touch事件的精确坐标计算、滚动动画的requestAnimationFrame平滑控制、以及iOS Safari特有的-webkit-overflow-scrolling: touch兼容性问题。手写这些,3天工期里至少花掉1天调试。
为什么不用Vue/React?因为一个通讯录列表页,核心交互就三件事:搜索过滤、索引跳转、详情页传参。用Vue写,你要建组件、写data、写computed、写methods,最后打包出来可能比zepto.min.js还大。而zepto.min.js(9KB)提供了足够精悍的API:$(selector).on('tap', handler)替代addEventListener('touchstart'),$('html, body').animate({scrollTop: pos}, 300)实现平滑滚动,$.param()快速序列化URL参数——全是微信H5最常用的操作,且无任何运行时依赖。
注意:本模板中
example.js仅包含业务逻辑(如搜索过滤算法、索引字母生成、详情页数据注入),所有DOM操作都通过zepto封装。例如索引跳转,不是简单document.getElementById(letter).scrollIntoView(),而是:javascript var $target = $(`[data-index="${letter}"]`); $('html, body').stop().animate({ scrollTop: $target.offset().top - 60 // 减去顶部搜索栏高度,确保目标元素完全可见 }, 300);
这个-60的偏移量,就是经过iPhone 12和华为Mate 40 Pro双端实测后确定的黄金值,确保无论屏幕尺寸如何,点击索引字母后,对应分组标题都稳稳停在搜索框下方。
2.3 资源组织:目录结构不是为了好看,而是为了“改一行代码就知道影响哪”
看一眼资源包目录树,你会发现它没用“assets”这种笼统名字,而是明确拆分为Css、Scripts、Images、Picture四个文件夹。这背后是血泪教训:
Css:只放样式文件(weui.css,example.css)。当设计师说“把搜索框背景改成浅灰”,你立刻知道去example.css找.weui-search-bar相关规则,不会误改weui.css导致全局崩溃。Scripts:只放JS文件(zepto.min.js,example.js)。当测试反馈“点击索引条没反应”,你直接打开example.js查initIndexBar()函数,不用在一堆vendor.js里大海捞针。Images:放所有UI控件图标(icon_nav_cell.png,icon_nav_search_bar.png等)。WeUI官方图标共23个,本模板全部收录,且命名与WeUI文档完全一致(如icon_nav_toast.png对应Toast组件图标)。这样当你需要在详情页加一个“复制邮箱”按钮时,直接引用<img src="Images/icon_nav_toast.png">即可,无需再PS导出。Picture:专放业务图片(vcode.jpg,pic.gif)。这是关键区分——UI图标和业务图片的更新频率、来源、版权属性完全不同。把二维码图片和cell图标混在一个文件夹,下次换LOGO时很容易误删图标文件。
这种结构,让一个刚接手项目的新人,5分钟内就能理解整个模板的脉络。它不是工程师的洁癖,而是降低协作成本的务实设计。
3. 核心功能实现详解:从字母索引到详情页,每一处细节的来龙去脉
3.1 字母索引栏(Index Bar):不只是“右边一列字母”,而是整套滚动体验的中枢
微信通讯录的索引栏,表面看是26个字母,实际承载了三个核心交互逻辑:快速定位、视觉反馈、滚动联动。本模板的实现,完全复刻了微信原生行为。
实现步骤拆解:
- HTML结构:在
index.html底部,用绝对定位固定索引栏:
```html- A
- B
- #
`` 关键点在于data-index属性,它不是随意加的,而是与联系人列表中每个分组的id完全对应(如
CSS定位与样式:
example.css中定义:css .contact-list__index-bar { position: fixed; right: 10px; top: 50%; transform: translateY(-50%); width: 24px; text-align: center; z-index: 100; } .contact-list__index-list li { font-size: 12px; line-height: 16px; color: #999; padding: 2px 0; user-select: none; /* 禁止长按选中 */ } .contact-list__index-list li.active { color: #09bb07; /* 微信绿色 */ font-weight: bold; }
这里user-select: none是关键。iOS Safari中,如果允许选中,用户快速滑动索引栏时会意外触发文字选择光标,打断操作流。JavaScript交互逻辑(
example.js):核心函数initIndexBar()包含三重能力:
-触摸跟踪:监听touchstart和touchmove,计算手指在索引栏Y轴位置,映射到最近的字母。
-实时高亮:根据当前触摸字母,动态添加.active类,并触发对应分组滚动。
-松手吸附:touchend后,自动滚动到最接近的分组顶部,并保持高亮状态2秒后淡出。
实操心得:早期版本用
mouseenter事件,结果在安卓部分机型上完全失效(因为touch事件不触发mouseenter)。必须用touchstart/touchmove原生事件。另外,“吸附2秒”不是拍脑袋定的——测试发现,少于1.5秒用户来不及看清高亮字母,超过2.5秒又会觉得响应迟滞,2秒是平衡点。
为什么索引栏要固定在右侧?
这不是UI设计选择,而是人体工学。拇指在手机右侧操作最自然,索引栏放这里,用户单手就能完成“滑动-定位-松手”全流程。如果放左侧,右手持机时几乎无法触及。
3.2 联系人列表页(index.html):分组、搜索、点击跳转的三位一体
列表页是整个模板的“门面”,它必须同时满足三个看似矛盾的需求:信息密度高(显示足够多联系人)、操作路径短(点击1次进入详情)、视觉不杂乱(分组清晰、留白舒适)。
分组逻辑:
所有联系人数据硬编码在index.html的<script>标签内(便于演示,实际项目可替换为AJAX请求):
var contacts = [ {name: "张三", department: "技术部", position: "前端工程师", phone: "138****1234", email: "zhangsan@company.com"}, {name: "李四", department: "市场部", position: "市场总监", phone: "139****5678", email: "lisi@company.com"}, // ... ];分组算法在example.js中:
function groupContacts(contacts) { var groups = {}; contacts.forEach(function(contact) { var firstChar = contact.name.charAt(0).toUpperCase(); // 处理中文姓名:用拼音首字母(需引入pinyin.js,模板已预置) if (/[\u4e00-\u9fa5]/.test(firstChar)) { firstChar = getPinyinFirstLetter(contact.name); // 示例函数 } if (!groups[firstChar]) groups[firstChar] = []; groups[firstChar].push(contact); }); return groups; }注意:中文姓名首字母提取是最大坑点。早期用正则
/^[\u4e00-\u9fa5]/只能判断是否中文,不能取拼音。模板内置了轻量pinyin.js(仅2KB),专门处理这个。如果你的项目不需要中文,可直接删除此依赖,性能提升15ms。
搜索过滤:
顶部搜索框(<div class="weui-search-bar">)的过滤逻辑非常克制:
- 输入≥2个字符才触发过滤(避免单字“张”匹配“张三”“章鱼”“障眼法”);
- 过滤字段为name+department+position(不搜手机号,防止隐私泄露);
- 过滤后,不隐藏分组标题,只隐藏无匹配项的分组。这是微信原生逻辑——让用户始终知道“我在哪个字母区间”,避免迷失。
点击跳转与数据传递:
点击联系人,跳转details.html并传递ID:
$('.contact-item').on('tap', function() { var id = $(this).data('id'); window.location.href = 'details.html?id=' + id; });这里用tap而非click,是因为click在移动端有300ms延迟(为兼容旧版桌面浏览器),而tap是zepto针对触摸优化的即时事件。
3.3 详情页(details.html):不只是展示字段,更是微信式交互的教科书
详情页常被当成“静态页面”,但微信的细节恰恰藏在交互里。本模板的details.html实现了四个微信原生特性:
头像点击放大:
<img src="Picture/vcode.jpg" class="detail-page__avatar" onclick="showImage(this.src)">showImage()函数调用WeUI的weui.previewImageAPI,实现原生相册式全屏预览。注意:vcode.jpg是示例图,实际项目中应替换为真实头像URL。手机号一键拨号:
html <a href="tel:138****1234" class="weui-cell"> <div class="weui-cell__hd"><img src="Images/icon_nav_phone.png" alt=""></div> <div class="weui-cell__bd">手机号</div> <div class="weui-cell__ft">138****1234</div> </a>
关键是href="tel:..."。微信内置浏览器会自动识别并唤起拨号界面;而安卓UC等浏览器会提示“是否用电话APP打开”,体验一致。邮箱一键复制:
```html邮箱zhangsan@company.com
``copyText()函数使用document.execCommand(‘copy’),并在iOS上兼容clipboard.writeText()`(需HTTPS环境)。模板已做降级处理:复制成功后toast提示,失败则alert友好提示。
- 底部操作区(Actionsheet):
页面底部预留区域,插入WeUI标准Actionsheet:
```html发送消息添加到通讯录分享名片取消
`` 点击“更多”按钮即可唤起。所有图标(icon_nav_msg.png,icon_nav_icons.png)均已放入Images` 文件夹,开箱即用。
4. 实操部署与避坑指南:从双击运行到嵌入现有项目
4.1 本地快速预览:为什么“双击就能跑”如此重要?
很多模板要求npm install && npm run dev,这对前端是常态,但对产品经理、UI设计师、甚至测试同学,就是一道墙。本模板的index.html设计为零依赖本地运行:
- 所有CSS/JS资源路径均为相对路径(
Css/weui.css,Scripts/zepto.min.js); - 图片路径统一为
Images/xxx.png或Picture/xxx.jpg; - 无任何外部CDN请求(连Google Fonts都没有);
- 使用
file://协议即可加载(Chrome需启动时加--unsafely-treat-insecure-origin-as-secure="file://"参数,但微信调试器和Safari完全支持)。
实操心得:曾有个客户要求“今天下班前给我看个demo”,我直接把压缩包发过去,对方双击
index.html就看到了完整效果,全程没装任何软件。这种交付速度,是技术方案商业价值的直接体现。
4.2 嵌入现有WeUI项目:三步走,不改一行原有代码
假设你已有基于WeUI的H5项目,想把本模板的通讯录集成进去,只需三步:
复制资源:
将模板的Css/example.css,Scripts/example.js,Images/(全部图标),Picture/(业务图片)四个文件/夹,复制到你项目对应目录下。引入新资源:
在你项目的入口HTML中,<head>里加入:html <link rel="stylesheet" href="Css/example.css">
在</body>前加入:
```html
```
- 创建新路由:
新建contact/index.html,内容为你项目原有的HTML结构,但<body>内容替换为模板的index.html中<body>部分(即保留你的header/footer,只换中间通讯录区域)。然后调整example.js中的初始化函数,将initContactList()绑定到你的新容器上。
注意:不要直接用模板的
index.html替换你整个页面!WeUI项目通常有自己的导航栏、tabbar,强行替换会导致样式冲突。正确做法是“取其神,不取其形”——只复用它的列表逻辑和样式类名,融入你的整体布局。
4.3 常见问题排查速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 索引栏点击无反应 | zepto.min.js未正确加载,或example.js中initIndexBar()未执行 | 检查浏览器控制台是否有404错误;确认example.js是否在zepto.min.js之后引入;在example.js开头加console.log('zepto loaded:', typeof $)验证 |
| 搜索框输入后无过滤效果 | contacts数据数组为空,或filterContacts()函数未绑定到搜索框的input事件 | 打开控制台,输入contacts查看数据是否存在;检查example.js中$('.weui-search-bar__input').on('input', ...)是否存在 |
| 详情页头像不显示 | Picture/vcode.jpg路径错误,或图片格式不被微信支持(如WebP) | 将图片重命名为vcode.jpg,确保是JPEG格式;检查路径是否为Picture/vcode.jpg(注意大小写) |
| iOS上点击手机号无拨号弹窗 | href="tel:..."的链接被其他JS阻止了默认行为(如event.preventDefault()) | 检查是否有全局事件监听器拦截了a标签的点击;临时注释掉其他JS,确认是否为本模板问题 |
| 安卓部分机型索引栏滚动卡顿 | transform: translateY(-50%)在旧版安卓WebView中性能差 | 将索引栏CSS改为top: 50vh; margin-top: -100px;(根据实际高度调整),牺牲一点灵活性换取流畅度 |
最后一个技巧:微信调试器有时缓存严重。遇到样式不生效,先清空微信缓存(我试过,清缓存比重启微信管用10倍)。
5. 扩展与定制建议:让模板真正属于你的项目
这套模板的价值,不在于它“多完美”,而在于它“多好改”。以下是几个高频定制场景的实操建议:
场景一:对接真实API
模板数据是静态的,但实际项目肯定要拉后端数据。在example.js中找到loadContacts()函数,将其替换为:
function loadContacts() { $.ajax({ url: '/api/contacts', type: 'GET', dataType: 'json', success: function(data) { contacts = data; // 假设后端返回数组 renderContactList(); // 重新渲染列表 initIndexBar(); // 重新初始化索引栏 }, error: function() { weui.toast('加载失败,请重试', 2000); } }); }关键点:renderContactList()必须在数据加载后调用,否则索引栏找不到对应id元素。
场景二:增加“部门筛选”Tab
在index.html顶部搜索框下方,插入WeUI Tab组件:
<div class="weui-tab"> <div class="weui-tab__panel"> <div class="weui-tab__content" style="display:block;">全部联系人</div> <div class="weui-tab__content">技术部</div> <div class="weui-tab__content">市场部</div> </div> <div class="weui-tab__bar"> <a href="javascript:void(0);" class="weui-tab__item weui-tab__item_active"> <div class="weui-tab__icon"> <img src="Images/icon_nav_cell.png" alt=""> </div> <p class="weui-tab__label">全部</p> </a> <a href="javascript:void(0);" class="weui-tab__item"> <div class="weui-tab__icon"> <img src="Images/icon_nav_button.png" alt=""> </div> <p class="weui-tab__label">技术</p> </a> </div> </div>然后在example.js中绑定Tab切换事件,调用filterByDepartment(deptName)函数。图标已备好,直接引用。
场景三:适配深色模式
WeUI本身不支持深色模式,但你可以用CSS媒体查询:
@media (prefers-color-scheme: dark) { .weui-cell { background-color: #1a1a1a; } .weui-cell__bd, .weui-cell__ft { color: #eee; } }加到example.css底部即可。注意:微信内置浏览器目前不支持prefers-color-scheme,所以这只是为未来兼容准备。
我个人在实际使用中发现,最省事的定制方式是——永远优先用WeUI原生类名,其次用example.css扩展,最后才考虑改weui.css。因为WeUI的类名就是微信的“语言”,你写的越多原生类,未来升级越轻松。这个模板,本质上是一份用代码写成的WeUI使用说明书,而你,就是它的第一位读者和编辑者。
本文还有配套的精品资源,点击获取
简介:直接可用的微信H5通讯录界面方案,严格遵循WeUI设计规范,适配iOS和安卓主流机型。首页index.html提供带右侧字母快速导航栏的联系人列表,支持按首字母分组、顶部搜索框触发筛选;点击任一联系人跳转details.html,展示头像、姓名、部门、职位、手机号、邮箱等标准信息字段,并预留扩展区域。资源包内置weui.css官方样式库、zepto.min.js轻量交互脚本、全套WeUI导航图标(含搜索栏、cell、toast、dialog等共20+个png图标)、示例图片(vcode.jpg、pic.gif)及辅助样式example.css。文件结构清晰划分Css、Images、Picture、Scripts目录,所有HTML页面双击即可本地运行,也兼容微信内置浏览器及各类基于WeUI的混合开发项目,无需编译或额外配置就能呈现原生微信视觉与操作反馈。
本文还有配套的精品资源,点击获取