模拟可编辑div输入域同时输入文字表情

近期遇到了模拟可编辑div输入域同时输入文字表情的需求,本来还觉得很好做,但是在具体实施的过程中遇到了一点问题。

第一个比较简单的问题是表情和对应字符的映射关系,这部分比较好做,没有用富文本框也没有用编辑器,做了表情和相应字符的对应关系只有就可以实现这个需求。

第二个问题在解决过程中就比较棘手了,因为是自己模拟输入域,所以对于在文字中加入表情后光标的定位及后续的输入是有要求的,就是得符合正常的输入习惯。这个问题的核心就是对于node节点的操作和光标对象的熟悉程度及其内部属性和方法的使用。对于前端开发者来说其实是很基础的一个知识点(此处羞愧脸)。不熟悉的同学其实也不要有心里负担,其实本来这写知识点及其使用网上一大推,但是不一定能够满足自己要的需求。对于这第二个问题来说,我的需求就是,在任何地方都可以做到想插入文字一样插入表情,而且光标像插入文字一样定位到表情后面。这么说浅显易懂吧。还不懂的话上图来理解一下

就是这样,将光标定位到“の”后面,插入表情,然后光标位置定位在表情后面。会的人会觉得很简单(膜拜大佬),不会的也有思路:就是监听光标位置,首先记录光标的初始位置,然后插入表情,然后计算长度,接着在定位光标。刚开始我就是这么想的,但是做了你就会发现一个问题,对于range对象来说对于非文本节点的计算光标是一个大问题。那么接下来我们来普及一下range这个对象(好开心,又认识了一个对象??)。

这是对range的定义:

Range 对象

Range 对象表示文档的连续范围区域,如用户在浏览器窗口中用鼠标拖动选中的区域。

Selection对象

所对应的是用户所选择的 ranges (区域),俗称拖蓝。默认情况下,该函数只针对一个区域,我们可以这样使用这个函数:

大致上来说range和selection都是区域

range里的属性等等还可以操作光标,做一些索引,位置的定位,输出等,这样你就可以在特定位置插入你想插入的节点了。

我们假设你已经做好了表情和对应字符的转换,列如对应的是[微笑]。而且我们假设你可以选取一段文字中光标的位置。接下来你讲在这个位置插入表情符号,成功了。这时候有人就说了,你这不废话么,肯定成功啊,如此清晰明确的逻辑和操作。但是如果看效果的话,你接下来插入的表情一般都不会成功。因为光标只会读取文本节点,当你插入了非文本节点。在次定位光标时,问题就在于,你插入的非文本节点会对你光标位置的输出造成干扰。也就是说不能指哪打哪。我们来看以下几种情况:

这是光标定位在1111111的第四个1之后的selection。我们可以通过focusOffset等诸多属性来在确切位置插入。完全没问题。但是注意看data属性,值是1111111,只是部分文本节点,这很符合逻辑,因为1111111和222222本来就是两个文本节点,没有normalize在一起。

接下来这种情况

输出的data,嗯,没毛病,是222222, anchorOffset是3????思考一下,你会发现,是根据当前定位节点来计算的,没毛病。那插入位置只能你自己计算喽,加上第一个文本节点,在加上第二个元素的长度,嗯,然后定位光标。居然发现报错了,这是因为把第二个元素的长度完全解析成了img标签的长度,所以,没一个文本节点的光标都是从零开始,并且非文本节点还不计算在内。经过我的努力,用这种数字的定位是解决不了的。

找了一些可以规避这个问题的方法,发现最优的可以将表情插入,并且光标的位置定位在表情后面,但是不能做到在任何位置插入表情。找了半天,找到了不同点。但是参考别人做的,和我的不一样应该是我用了一种取巧的办法。下面上代码:

function insertHtmlAtCaret(html) {
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
// Range.createContextualFragment() would be useful here but is
// non-standard and not supported in all browsers (IE9, for one)
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if (document.selection && document.selection.type != "Control") {
// IE < 9
document.selection.createRange().pasteHTML(html);
}
}
$(".abc").click(function (){
// $(".abc").trigger(‘click‘);
document.getElementsByClassName(‘test‘)[0].focus(); insertHtmlAtCaret(‘<img src="wdwe.png">‘);
});

insertHtmlAtCaret方法是个黑箱,想了解内容的具体逻辑可言去学习一下。但是刚开始的时候我用这个方法也遇到了一点问题。点击的表情总是会加在内容的最前面。这里有一个注意点,那就是类名为abc的元素必须是input type=‘button‘的元素。

希望遇到和我一样问题的人,看到了这篇文章会对你的编码有帮助,如果有不明白的欢迎一起探讨。

原文地址:https://www.cnblogs.com/wyliunan/p/9561894.html

时间: 2024-08-15 06:57:01

模拟可编辑div输入域同时输入文字表情的相关文章

html中表格与输入域常用元素总结

<!doctype html> <html>    <head>       <meta http-equiv="content-type" charset="utf-8";>       <title></title>    </head>    <body>       <table>          <thead>*表头          

html旅程之输入域控件

在html的学习中,我们会遇到很多控件的学习.其中有一类叫做输入域的控件,可以承载用户输入的数据,也可以通过html改变数据的传递方式,或者它本身的样式. 我们可以根据性质将该类控件分为:文本型.按钮型.选择型三个小类: 其中每一种控件与VB控件的对应关系表示为: 一.文本型 这种类型的控件都是以文本的形式呈现,可以直接将用户输入的文本数据承载下来,然后进行传递. 1.form:表单 主要属性有:action.method(get和post).type.name.   PS:get和post的区

css相关,鼠标点击&lt;input&gt;输入域后出现有颜色的边框

css相关,鼠标点击<input>输入域后出现有颜色的边框,如果使用css,将这个鼠标点击输入域后产生的边框去掉呢?下面是截图 鼠标未点击前: 鼠标点击后: 根据大家的办法实现不了的,即使可以改变颜色,但是那条有颜色的线还是无法消除.下面是我的html和css代码: html: <input type="text" name="content" id="input_box"> css: #input_box{ border

vc+如何实现模拟键盘输入,自动输入文字(创世纪篇)

键盘对于每个操作电脑的人员来说是最熟悉不过的了.键盘上的按键可分为两类: 按下后会在电脑的输入窗口上出现对应字符的按键,如字母键和数字键等,我们称之为字符键:按下后虽然看不到字符但会产生控制作用的按键,如回车键.光标键等,我们称之为控制键. 对于vc+程序员来说,键盘上的每个按键都一样,无非是不同按键产生的键盘扫描码不同.在不同的操作系统下,键盘扫描码常常被转换为不同的编码以方便应用程序调用,比如在Windows系统下的ASCII码,在Windows系统下的虚拟键盘码等等. 有时我们希望能以程序

模拟Select-Options对象实现多项数据输入功能

SPAN { font-family: "Courier New"; font-size: 10pt; color: #000000; background: #FFFFFF } .L0S31 { font-style: italic; color: #808080 } .L0S32 { color: #3399FF } .L0S33 { color: #4DA619 } .L0S52 { color: #0000FF } .L0S55 { color: #800080 } .L0S7

在混合开发中软键盘引起的布局问题、input与可编辑DIV兼容性问题汇总

此文复现的所有兼容性问题均为以下情况: 1. 腾讯X5内核 2. 全屏webview 问题如下: 1. IOS12 中软键盘弹出导致页面顶部截断,并且无法恢复. 解决方法:添加交互事件,调用本地方法,在键盘收起后执行页面回滚操作. bridgeClass.jsEventHook.keyboardWillShow = function () { // 添加flag 是因为 有多个空时,切换输入框也会调用WillHide switchFlag = true; }; bridgeClass.jsEve

JavaScript-3.1--获取用户的输入,输出用户输入的两数之和---ShinePans

提示用户输入两个数,然后输出用户输入的两数之和 第一次输入 ,输入处为空 第二个输入,输入处为默认27  (这里强调语句的使用) <html> <head> <meta http-equiv="content-type" content="text/html;charset=GB2312"/> <title> 3.1 让用户输入两个数字,然后输出相加的结果 </title> </head> &l

可编辑div将光标定位到最后

最近做了一个可以回复留言的页面,主要包括:@.表情功能,一开始使用的是文本域textarea,最后发现这样无法显示表情,后来改成可编辑div,在div中添加contenteditable="true",则该div即可编辑. <div contenteditable="true"></div> 在选择表情或者选择@某人后,会经常遇到选择后可编辑div中的光标不见了,或者显示的位置不对,于是在网上找了些方法,现在总结下: function set

只允许input框输入数字,输入其他的键的时候,直接不显示的方法

function numInteger(){ if((event.keyCode>=48 && event.keyCode<=57)  || (event.keyCode>=96 && event.keyCode<=105)) { return true; }else if(event.keyCode==8 || event.keyCode==9){     //保留回格键和tab键 return true; }else{ event.returnV