手把手教你用js实现手机通讯录功能(附源码)
js实现手机通讯录
- 效果图
- 需求
- 需求一:锚点
- 通过#id配合a标签使用
- css中scroll-behavior属性的使用
- 需求二+需求三
- 获取汉字拼音的首字母
- 方法1:使用插件,这里推荐pinyin-pro
- 方法2:使用unicode
- 去重数组中冗余的对象
- 法一:用Map去重
- 法二:用双层for循环配合splice使用
- 代码实现
- Html,css
- js需要引入的工具代码
效果图

需求
手机通讯录这样的功能在很多场景下都是可以见到的,多出现在移动端,它通常有以下特点:
- 锚点 ,点击右侧的英文字母,会跳转到相应的区块,并且在此过程,页面不刷新;
- 智能识别左侧的地名,或者人名。在相应首字母不存在的情况下,不会出现相应的首字母列表,比如下图,没有字母E,F对应的人名或则地名,则不显示E,F空列表
- 数据流精准定位可以随意添加数据,自动根据人名或者地名汉语拼音的第一个首字母来准确定位,并将当前人名或地名精准存放在相应的字母列表当中;
需求一:锚点
锚点是css里一个非常神奇的功能。实现这样的功能,我一般做好以下两点,基本就是完美的了。
通过#id配合a标签使用
<nav><a href="#1">1</a><a href="#2">2</a><a href="#3">3</a><a href="#4">4</a><a href="#5">5</a></nav><div><div id="1">1</div><div id="2">2</div><div id="3">3</div><div id="4">4</div><div id="5">5</div></div>
这一看就明白,a标签用于右侧字母导航栏。a标签里href的属性值,用#id表示,分别与左侧列表里的div的id名字一一对应,即可实现点击跳转,这一特点也叫锚点,这在css里还是挺高级的。
css中scroll-behavior属性的使用
使用这个属性,可以让你的锚点跳转看起来更加丝滑
:root{font-size: 2rem;scroll-behavior: smooth;}
MDN官网是这样介绍的:
当用户手动导航或者 CSSOM scrolling API 触发滚动操作时,CSS 属性 scroll-behavior 为一个滚动框指定滚动行为,其他任何的滚动,例如那些由于用户行为而产生的滚动,不受这个属性的影响。在根元素中指定这个属性时,它反而适用于视窗。
/* Keyword values */
scroll-behavior: auto;
scroll-behavior: smooth;/* Global values */
scroll-behavior: inherit;
scroll-behavior: initial;
scroll-behavior: unset;
换句话说,如果不使用这个属性,那么在锚点跳转过程中,会突然跳转到相应位置,非常生硬,用户体验感比较差。
如果使用这个属性,在锚点跳转过程中,会有过渡效果。使得整个过程看起来更加合理,丝滑。
需求二+需求三
先分析这这两个需求应该如何实现?
智能识别,以及数据流精准定位
1. 先获取地名或者人名汉字拼音的第一个汉字的首字母
2. 将此首字母打印,没有问题,然后将其放在一个变量里
3. 准备26个英文字母,将这个字符串分割成26个元素,然后遍历一下这个数组。
4. 遍历第一个汉字拼音的首字母
5. 再拿26个字母 与 第一个汉字拼音的首字母比较
6. 如果两个字母相同,将第一个汉字拼音的首字母 对应的地名 放入一个新数组
7. 做个判断。当某个首字母对应的汉字为空,则不渲染这个字母列表
8. 如果数组中的对象有重复,调用去重函数
9. 输出
分析
难点1:这里面循环判断输出都没有什么难以实现的,难度不大。难的是如何将汉字转化为拼音,并获取到拼音的首字母
难点2:如果出现重复,怎么去重?
难点3:有没有别的方式优化程序,可以跳过去重
获取汉字拼音的首字母
方法有二:
方法1:使用插件,这里推荐pinyin-pro
<script src="https://unpkg.com/pinyin-pro@3.12.0/dist/index.js"></script>
这是一款具有非常强大的汉字转换方法的插件,用路径在线引入即可使用。并且pinyin-pro 支持各种浏览器以及 Nodejs 环境运行。
方法2:使用unicode
unicode这是一种文字编码标准,是以\u6211\u559c\u6b22\u4f60等形式出现的
eg:
\u6211\u559c\u6b22\u4f60 == 我喜欢你
\u6211\u7231\u4f60 == 我爱你
\u4f60\u597d\u5e05\u554a == 你好帅啊
\u6211\u6211\u559c\u6b22\u5403\u70b8\u9171\u9762 == 我喜欢吃炸酱面
这就是uniode,我个人更喜欢用第二种方式。将文字编码打包成一个文件,需要的时候随时本地调用即可,非常安全。
去重数组中冗余的对象
这里推荐两种去重方法
法一:用Map去重
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title></title>
</head>
<body></body>
</html>
<script>let obj = [{ name: "米面", id: 1 },{ name: "牛肉", id: 2 },{ name: "蔬菜", id: 3 },{ name: "水果", id: 3 },{ name: "饮料", id: 1 },{ name: "咖啡", id: 4 },{ name: "茶叶", id: 3 }];const map = new Map();const newArr = obj.filter(csdn => !map.has(csdn.id) && map.set(csdn.id, 1));console.log(newArr);
</script>
输出结果:

法二:用双层for循环配合splice使用
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title></title>
</head>
<body></body>
</html>
<script>let obj = [{ name: "米面", id: 1 },{ name: "牛肉", id: 2 },{ name: "蔬菜", id: 3 },{ name: "水果", id: 3 },{ name: "饮料", id: 1 },{ name: "咖啡", id: 4 },{ name: "茶叶", id: 3 }];function fn1(tempArr) {for (let i = 0; i < tempArr.length; i++) {for (let j = i + 1; j < tempArr.length; j++) {if (tempArr[i].id == tempArr[j].id) {tempArr.splice(j, 1);j--;};};};return tempArr;};console.log(fn1(obj));
</script>
输出结果:

两种去重方法,得到的结果是一模一样的。这两种方法可以复制后,直接调用。值得一提的是除了Map还有set 还有for of /forEach /for in等方法,虽然各有特点,但都有自己的最合适的使用场景,详情可阅读前文,有详细介绍。
我个人更喜欢用第二种方法,因为用双层for循环配合splice去重的方法,是最不耗费性能的。虽然结构复杂,让人看的恶心,但毕竟“省钱”。
代码实现
按照分析的思路去执行即可,怎么想就怎么做
程序如人生
Html,css
<!doctype html>
<html><head><meta charset="utf-8"><title></title><style>:root{font-size: 2rem;scroll-behavior: smooth;}#right>a {display: block;text-decoration: none;color: black;text-align: center;}#right {position: fixed;right: 0.2rem;top: 1vh;font-size: .7rem;display: flex;flex-wrap: wrap;align-items: center;width: .5rem;padding: 0% 1rem;text-align: center;height: 100vh;background-color: greenyellow;overflow-y: scroll;}#list p {background: -webkit-linear-gradient(left, #2b80ff, #8098aa);}#list {height: 500vh;font-size: 2rem;}</style></head><body><div id="list"><!-- <p>A</p><span></span><span></span><p>B</p><span></span><span></span> --></div><div onclick="data()" id="kl" style="display: block;position: absolute;top: 0%;+6"><button>来吧,展示</button></div><div id="right"><a href="#A">A</a><a href="#B">B</a><a href="#C">C</a><a href="#D">D</a><a href="#E">E</a><a href="#F">F</a><a href="#G">G</a><a href="#H">H</a><a href="#I">I</a><a href="#J">J</a><a href="#K">K</a><a href="#L">L</a><a href="#M">M</a><a href="#N">N</a><a href="#O">O</a><a href="#P">P</a><a href="#Q">Q</a><a href="#R">R</a><a href="#S">S</a><a href="#T">T</a><a href="#U">U</a><a href="#V">V</a><a href="#W">W</a><a href="#X">X</a><a href="#Y">Y</a><a href="#Z">Z</a></div></body>
<html>
js需要引入的工具代码
<script src="./data.js"></script> //人名,地名的假数据<script src="./unicode.js"></script> //汉字转换拼音的打包文件,含有编码和方法<script src="./jquery-3.6.1.js"></script> //引入jquery文件,方便简化代码
这三个文件比较大,我放在资源里了,可以免费下载,希望对大家有帮助
其次还需要一个实现功能的js文件
注释也是必不可少的
<script>// ----------数组中相同对象去重,选择两层for循环配合splice使用// function deWeight(arr) {// for (var i = 0; i < arr.length - 1; i++) {// for (var j = i + 1; j < arr.length; j++) {// if (arr[i].one == arr[j].one) {// arr.splice(j, 1);// j--;// }// }// }// return arr;// }//---------------------function data() {document.querySelector('#kl').style.display = 'none'// --------把地名拼音第一个首字母放到a数组里let a = [];for (let j = 0; j < arrs.length; j++) {var chinaName = arrs[j].name;var easyName = pinyin.getCamelChars(chinaName);// console.log(easyName);// console.log(easyName); //每个地名拼音的首字母缩写 a.push(easyName[0]) //第一个汉字拼音的首字母}//------------// let obj = {}let add = [];//-----------遍历一下26个字母,let strarr = 'ABCDEFGHIJKLMNOPQRSTUVWSYZ'.split('');for (let i = 0; i < strarr.length; i++) {//-------------//----------遍历第一个汉字拼音的首字母let names = [];for (let j = 0; j < a.length; j++) {//----------//----------26个字母 与 第一个汉字拼音的首字母比较if (strarr[i] == a[j]) {//----------如果两个字母相同,将第一个汉字拼音的首字母 对应的地名 放入数组names eg:B 北京 B北海道 names= [北京,北海道]names.push(arrs[j].name)//----------console.log(names);}//----------}if (names.length != 0) {//----------B == 北京 one:B two:[北京,北海道] B == 北海道 one:B two:[北京,北海道]let obj = {one: strarr[i],two: names}//----------//----------将对象放入数组add.push(obj)// console.log(add);//----------}}console.log(add);//----------//----------调用去重函数,将数组里重复的对象去除// deWeight(add);//----------//----------输出let str = '';for (let i = 0; i < add.length; i++) {str += `<p id = ${add[i].one}>${add[i].one}</p><span>${add[i].two.join('<br/>')}</span>`}$("#list").html(str)//----------}// data()</script>
创作不易,如果对你有帮助,请三连支持。

相关文章:
手把手教你用js实现手机通讯录功能(附源码)
js实现手机通讯录效果图需求需求一:锚点通过#id配合a标签使用css中scroll-behavior属性的使用需求二需求三获取汉字拼音的首字母方法1:使用插件,这里推荐pinyin-pro方法2:使用unicode去重数组中冗余的对象法一:用Map去…...
【C/C++】逗号表达式、算术运算符优先级
一、逗号表达式 1、如下图中代码,为变量d赋值,d的值为逗号表达式中的哪一个呢? 运行结果:d的值为6 2、再举个例子 运行结果:d的结果还是6 3、再举个例子 运行结果 以上面三种不同的逗号表达式为例,…...
携禾生物面试总结
面试时间: 2022年2月3日 1.项目C11的特性具体有用到哪些? 智能指针 lambda表达式 auto unordered_map 2.智能指针用到了哪几种智能指针 3.shared_ptr和weak_ptr区别 4.多线程实现方式 prosix线程》pthread windows的_beginthreaex MFC多线程 ACEM中…...
FPGA纯verilog手写HDMI发送IP 提供源码和技术支持
目录1、前言2、设计思路和框架TMDS 编码算法OSERDESE串并转换3、顶层源码和IP封装4、源码和IP获取1、前言 本设计使用Xilinx原语和自己手写的代码实现了HDMI发送功能,纯verilog手写,有源码,也提供封装好的IP,你喜欢用例化的方式就…...
【知识点】OkHttp 原理 8 连问
前言OkHttp可以说是Android开发中最常见的网络请求框架,OkHttp使用方便,扩展性强,功能强大,OKHttp源码与原理也是面试中的常客但是OKHttp的源码内容比较多,想要学习它的源码往往千头万绪,一时抓不住重点.本文从几个问题…...
【python】深入了解Selenium-PageObject
1、PageObject 定义 Page Object(简称PO)模式,是Selenium实战中最为流行,并且是自动化测试中最为熟悉和推崇的一种设计模式。在设计自动化测试时,把页面元素和元素的操作方法按照页面抽象出来,分离成一定的对象,然后再…...
PAT——7-4 简易测谎 (20 分)
测谎通常使用一套准备好的问题提问被测试者,通过分析被测试者的反应得到结果。比较高级的测谎技术会使用测谎仪,监视被测试者的生理活动状况。我们这里的简易测谎则是通过对问题答案的特征分析来做出判断。 首先我们要求被测试者做完 N 道单选题&#x…...
【力扣】 面试题 05.02.二进制数转字符串(超过c++100%)
二进制数转字符串。给定一个介于0和1之间的实数(如0.72),类型为double,打印它的二进制表达式。如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”。示例1:输入:0.625输出:"0.10…...
软件质量保证与测试 课堂笔记
...
Costco好市多验厂百问百答
【Costco好市多验厂百问百答】美国仓储式超市Costco,中文好市多,近几年发展势头迅猛,大有赶超传统商超巨头沃尔玛之势。之前有出口企业反馈,Costco采购不仅量大,而且价格好,所以Costco成为国内出口企业纷纷…...
Nginx 通过 header 中的标识进行分发
Nginx可以根据请求头中自定义的标识将请求分发到不同的服务器。具体来说,可以使用map指令将请求头中的自定义标识映射为不同的后端服务器地址,然后使用proxy_pass指令将请求转发到对应的后端服务器。 以下是一个示例配置文件: http {map $h…...
如何实现《电子签名法》要求的可靠电子签名?
电子文档的电子签名怎么弄?我们在工作中经常需要在一些Word、pdf等电子版文件中插入签名,而很多人可能不知道,电子签名怎么弄?怎么做电子签名才有效?电子印章或签名图片属于电子签名吗?当工作或商务交易中&…...
工程项目管理软件有哪些?这六款很好用!
工程项目管理软件哪个好用?这六款很不错! 在现代社会中,软件已经成为了企业信息化、项目管理等方面必不可少的工具。尤其是对于工程项目管理而言,借助软件进行协同、计划、控制等方面的工作,已经成为了必要的手段。但…...
多看看spdk代码学习
多看看spdk代码学习还是干货直接上代码简易讲解详细讲解一下这份代码还是干货直接上代码 #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <stdbo…...
宾语从句it做形式主语的句子
It代替从句作形式主语的常见句型 一、it 代替连词 that 引导的从句作形式主语。 1、it be 过去分词 that 从句: It’s said that Tom has come back from abroad . It was reported that dozens of children died in the accident . 可用于该句型的过去分词还有…...
【C#基础】C# 文件与IO
序号系列文章9【C# 基础】C# 异常处理操作10【C#基础】C# 正则表达式11【C#基础】C# 预处理器指令文章目录前言1,文件和IO的概念2,文本文件操作2.1 File 类2.2 FileInfo 类2.3 FileStream 类2.4 StreamReader 类2.5 StreamWriter 类FileStream 和 Stream…...
死锁相关介绍【内含哲学家就餐问题】
死锁 死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。 场景1:一个线程,一把锁 一个线程,一把锁,线程…...
Java的Groovy执行器内存泄露(MetaSpace)问题分析与解决办法
环境与背景 在java程序中通过GroovyScriptEvaluator执行器创建脚本Script对象调用Groovy脚本语言来完成某些功能, ,会通过AppClassLoader或者GroovyClassLoader去生产一个随机的名称的Groovy的Script类对象,导致元数据,产生的class类会被AppClassLoader或者GroovyClassLoader内…...
【linux】进程信号——信号的产生
进程信号一、信号概念1.1 信号理解二、产生信号2.1 通过键盘产生信号2.2 捕捉信号自定义signal2.3 系统调用接口产生信号2.3.1 向任意进程发送任意信号kill2.3.2 给自己发送任意信号raise2.3.3 给自己发送指定信号abort2.3.4 理解2.4 硬件异常产生信号2.4.1 除0异常2.4.2 野指针…...
部署OpenStack
部署 1. 环境配置 配置主机名 使用CRT软件连接controller节点和compute节点,用户名默认为root,密码默认为000000。连接上之后,使用linux命令修改节点主机名。 [rootcontroller ~]# hostnamectl set-hostname controller [rootcontroller …...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...

