当前位置:网站首页>怎样实现网页端im即时通讯中的@人功能
怎样实现网页端im即时通讯中的@人功能
2022-06-22 18:55:00 【wecloud1314】
第一次使用@人功能到现在已经有差不多10年了,初次使用是通过微博体验的。@人的功能现在遍布各种应用,基本上涉及社交(IM、微博)、办公(钉钉、企业微信)等场景,就是一个必不可少的功能。

最近正好在调研 IM 各种功能的技术实现方案,所以也详细地了解了下@人功能在Web网页前端的技术实现,正好借此机会给大家分享一下我所掌握的技术原理和代码实现。
微博的实现比较简单,就是通过正则匹配,最后用空格表示匹配结束,所以实现上是直接使用了textarea标签。
但是这个实现必须依赖的一个事情是:用户名必须唯一。
微博的用户名就是唯一的,所以正则所匹配到的ID,一般的可以映射到唯一的一个用户上(除非ID不存在)。不过,微博中的这个功能整体输出比较宽松,你可以构造任何不存在的ID进行@操作。
通过分析业内的主流实现,@人功能的技术实现思路大致如下:
1)监听用户输入,匹配用户以@开头的文字;
2)调用搜索弹窗,展示搜索出来的用户列表;
3)监听上、下、回车键控制列表选择,监听ESC键关闭搜索弹窗;
4)选择需要@的用户,把对应的HTML文本替换到原文本上,在HTML文本上添加用户的元数据。
一般来说,如果像平常用的Lark搜索(Lark就是“飞书”),我们是不会通过唯一的『工号』去进行搜索,而是通过名字,但是名字会出现重复,所以就不太适合用textarea的方式,而是用contenteditable,把@文本替换成HTML标签特殊化标记。
代码实现第1步:获得用户的光标位置
想要获得用户输入的字符串,然后替换进去,第一步就是需要获得用户所在的光标。要获取光标信息,那就要先了解什么是『选择(Selection) 』和『范围(Range) 』。
范围(Range)
Range本质上是一对“边界点”:范围起点和范围终点。
每个点都被表示为一个带有相对于起点的相对偏移(offset)的父 DOM 节点。如果父节点是元素节点,则偏移量是子节点的编号,对于文本节点,则是文本中的位置。即时通讯开发

例如:
let range = newRange();
然后使用 range.setStart(node, offset) 和 range.setEnd(node, offset) 来设置选择边界。
假设 HTML 片段是这样的:
<pid="p">Example: <i>italic</i> and <b>bold</b></p>
解释一下:
1)range.setStart(p, 0) :将起点设置为 <p> 的第 0 个子节点(即文本节点 "Example: ");
2)range.setEnd(p, 2) : 覆盖范围至(但不包括)<p> 的第 2 个子节点(即文本节点 " and ",但由于不包括末节点,所以最后选择的节点是 <i>)。
我们需要创建一个范围:
1)从的第一个子节点的位置 2 开始(选择 "Example: " 中除前两个字母外的所有字母);
2)到 的第一个子节点的位置 3 结束(选择 “bold” 的前三个字母,就这些),代码如下。
选择(Selection)
Range 是用于管理选择范围的通用对象。
文档选择是由 Selection 对象表示的,可通过 window.getSelection() 或 document.getSelection() 来获取。
根据 Selection API 规范:一个选择可以包括零个或多个范围(不过实际上,只有 Firefox 允许使用 Ctrl+click (Mac 上用 Cmd+click) 在文档中选择多个范围)。
其他浏览器最多支持 1 个范围。
正如我们将看到的,某些 Selection 方法暗示可能有多个范围,但同样,在除 Firefox 之外的所有浏览器中,范围最多是 1。
与范围相似,选择的起点称为“锚点(anchor)”,终点称为“焦点(focus)”。
主要的选择属性有:
1)anchorNode:选择的起始节点;
2)anchorOffset:选择开始的 anchorNode 中的偏移量;
3)focusNode:选择的结束节点;
4)focusOffset:选择开始处 focusNode 的偏移量;
5)isCollapsed:如果未选择任何内容(空范围)或不存在,则为 true ;
6)rangeCount:选择中的范围数,除 Firefox 外,其他浏览器最多为 1。
看完上面,不知道了解了没?没关系,我们继续往下。
综上所述:一般我们只有一个 Range,当我们的光标在 contenteditable 的 div 上闪动的时候,其实就有了一个 Range,这个 Range 的开始和结束位置都是一样的。
另外:我们还可以直接通过 Selection.focusNode获取到对应的节点,通过 Selection.focusOffset 获取到对应的偏移量。
代码实现第2步:获取需要@的用户
在上一节我们获得了光标在对应Node节点的偏移量,以及对应的Node节点。那么就可以通过textContent方法获取整个文本。
Web前端富文本的坑确实比较多,之前没怎么了解过这部分的知识。虽然整个过程看起来很粗糙,但是技术原理就是这样。
不完善的地方很多,有更好的方式可以共同讨论下。
边栏推荐
- 数字化转型的失败原因及成功之道
- Connect function usage of socket
- Three dimensional world helps the laboratory to consolidate the complete quality system management
- Summary of 2019: 31 is just another start
- 元宇宙中的云计算,提升你的数字体验
- socket的connect函数用法
- Pit of undefined reference
- leetcode.11 --- 盛最多水的容器
- [in depth understanding of tcaplus DB technology] getting started tcaplus SQL driver
- 运用span-method巧妙实现多层table数据的行合并
猜你喜欢

Three months of self-taught automatic test, salary from 4.5K to 15K, who knows what I have experienced?

How should programmers look up dates

芯和半导体“射频EDA/滤波器设计平台”闪耀IMS2022

一张图解码 OpenCloudOS 社区开放日

Zabbix学习笔记(三十七)

Storage structure of graph (adjacency matrix)

基于Sentinel的高可用限流系统的Grafana报表展示

ZABBIX learning notes (37)

Possible security vulnerabilities in NFT

智能计算之神经网络(BP)介绍
随机推荐
树莓派环境设置
请你描述下从浏览器上输入一个url到呈现出页面的整个过程。
Shell Sort
How should programmers look up dates
Async-profiler介绍
软件上线前为什么要做性能测试?软件性能测试机构怎么找
【深入理解TcaplusDB技术】TcaplusDB运维
Matplotlib set axis scale interval
【深入理解TcaplusDB知识库】部署TcaplusDB Local版常见问题
【深入理解TcaplusDB技术】TcaplusDB进程
Three months of self-taught automatic test, salary from 4.5K to 15K, who knows what I have experienced?
JWT简介
[in depth understanding of tcapulusdb technology] tcapulusdb operation and maintenance
Simple integration of client go gin 11 delete
Search, insert and delete of binary sort tree
Google | ICML 2022: sparse training status in deep reinforcement learning
基于Sentinel的高可用限流系统的Grafana报表展示
三维天地助力实验室夯实完整质量体系管理
Interpolation lookup and half (bisection) lookup
Heap sort (principle plus code)