输入框插入表情的实现

在普通的 textarea 中,只能显示普通的文本。如果简单的输入文本,textarea 便足以胜任。但是实际情况往往要复杂得多。

简单版本的插入表情

常见的版本一般都是使用 textarea,然后表情使用某种约定的文本格式代替,比如“你好啊[微笑]”。在呈现的时候,通过固定的文本解析方法将内容中的表情文本替换成图片。新浪微博中发微博的输入框就是如此。但是,在这有一点需要注意,如果只是简单的在文本的最后插入表情之类的预定好的文本格式,只需获取到到 textarea 的 value 然后做加法即可。

let editor = document.querySelect('#editor');
editor.value += '[微笑]';

没你想的这么简单

但实际情况却没有这么简单,因为用户可以自己选择光标的位置。当用户在某一段文本中间插入光标之后,可不是简单的加法了。在这种情况下,需要获取到光标所在位置,在这个位置上插入用来代替表情的文本,然后将光标设置到表情文本的后面。在这需要两个额外的方法:getCaretPositionsetCaretPosition

getCaretPosition/setCaretPosition

浏览器并没有提供直接获取光标位置的方法,需要我们变通的处理。浏览器基本上都支持文本框的select()方法,这个方法用于选中文本框中所有的文本,但是只能乖乖的拿到返回的所有文本。HTML5 添加了两个属性:selectionStart 和 selectionEnd 帮助我们更加顺利地获取选择的文本。这两个属性中保存的是基于0的数值,表示所选择的文本的范围,分别表示文本选区(选中的文本)开头和结尾相对整个文本内容的偏移量(在整个文本内容中的位置)。例如:

let editor = document.querySelector('#editor');
// 从第一个字符开始,选中三个字符
editor.selectionStart = 0;
editor.selectionEnd = 1;

// 从第三个字符开始选中三个字符
editor.selectionStart = 2;
editor.selectionEnd = 5;

说到这你可能要问了,这个光标有啥关系啊?别急,听我慢慢说。既然上述两个设置不同数字可以选择文本,那如果两个值设置成相同的数字,会怎么样呢?

// 从第三个字符开始选中零个字符
editor.selectionStart = 2;
editor.selectionEnd = 2;

起点和终点重合了!那么换个角度来描述就是:当我们在获取光标位置的时候,其实就是选中的文本范围起点和重点重合,相当于文本范围的起点偏移量其实就是光标所在的位置偏移量,所以此时selectionStart的返回值就是我们需要的结果。

更关键的是,当 End 和 Start 设置成相同值时,选区也是空的,起点和重点充电,就好像是设置了光标的位置。其实有一个简便的方法 setSelectionRange(start, end),原理相同。

当然有兴趣你也可以试试 End小于 Start的情况。上述这些在现代浏览器和 IE9+ 上都支持。

前端向来麻烦的还是浏览器的兼容问题。在低版本的 IE 中只能使用 document.selection 对象来模拟光标定位了。document.selection 只存在于 IE8 及更早的版本(可以使用 window.getSelection 代替),保存着用户在整个文档范围内选择的文本信息,但是无法确定用户选择的是页面中哪个部位的文本。要想取得选择的文本,首先需要创建一个范围(Range,IE9+ 支持 DOM Range API,但是 IE8及之前的版本不支持,但是有类似的概念,text range。这是 IE 专有的特性)。可使用 document.selection.createTextRange 来创建我们所需要的 text range。然后利用moveStart().aspx)将文本的范围的起点从当前位置(当前位置起点和重点是重合的)移动到文本的开头,然后计算选中文本的长度,这个长度值可以用来代替当前光标的位置。

let range = document.selection.createRange();
range.moveStart("character", editor.value.length);
cursurPosition = range.text.length;

设置光标位置思路类似,但是代码稍有不同:

let range = editor.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();

总的来说,在 textarea 中获取和设置光标位置还是蛮简单的。讲到这里了,我想插入表情应该是很轻松的一件事情了

获取光标位置(文本范围前后重叠) -> 修改文本范围(或者手动拼接) -> 重新设置光标位置 

至此,表情插入功能的基本实现。

还没结束

上述例子中,在输入框中表情只能以文本的形式呈现。如果想在输入框中呈现输入的表情,该怎么办呢?使用 contenteditable 属性为 true 的容器代替 textarea 是必须的,因为 textarea 中只能显示文本。但是这就足够了吗?不,显然不够。没有了 textarea 则以为这没有了 setSelectionRange, selectionStart 和 selectionEnd。但是好在原理也是类似,依旧使用 Range API 或者 Text Range(IE8及其更低版本)。具体的可以参考这篇:html元素contenteditable属性如何定位光标和设置光标和这篇在可编辑的div中插入图片。 具体实现代码我就不贴了,大家可以自己思考捋一捋。举一反三,如果你真真正正地知道如何正确插入图片,那么插入复杂的 DOM 结构对你来说也是轻而易举。


219 声望
10 粉丝
0 条评论
推荐阅读
个人服务器常用基础配置
yum 源仓库里最新版本的 Git 是 1.8.3.1,但是官方最新版本已经到了 2.9.2。想要安装最新版本的的 Git,只有下载源码进行安装。

张伦3阅读 1.6k评论 3

从零搭建 Node.js 企业级 Web 服务器(零):静态服务
过去 5 年,我前后在菜鸟网络和蚂蚁金服做开发工作,一方面支撑业务团队开发各类业务系统,另一方面在自己的技术团队做基础技术建设。期间借着 Node.js 的锋芒做了不少 Web 系统,有的至今生气蓬勃、有的早已夭折...

乌柏木144阅读 12k评论 10

JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...

jenemy45阅读 5.8k评论 12

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木63阅读 6k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs39阅读 6.2k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木41阅读 7.2k评论 6

【关于Javascript】--- 正则表达式篇
基础知识一、元字符 {代码...} 二、量词 {代码...} 三、集合 字符类 {代码...} 四、分支 {代码...} 五、边界 开始结束 {代码...} 六、修饰符 {代码...} 七、贪婪模式和非贪婪模式js默认贪婪模式即最大可能的匹配...

Jerry35阅读 2.9k

219 声望
10 粉丝
宣传栏