javascript - 为什么 textarea 中的选择范围重置为 0?
问题描述
我有一些 IMG 表情符号,它们可以作为字符串表示形式插入到 textarea 中。下面的脚本必须获得插入符号位置并将表示插入正确的位置,但有时它会出错并将选择范围重置为 0。
您可以通过单击微笑和文本区域内的示例来查看它。在 textarea 内容的末尾设置插入符号后,我立即重置为 0。
window.onload = function() {
var doc = window.document;
var smiles = doc.getElementById('chat-smiles-panel').getElementsByTagName('IMG');
var el = doc.getElementById('chat-textarea');
for (var i = 0; i < smiles.length; i++) {
smiles[i].onclick = function(e) {
var elem, evt = e?e:event;
elem = (evt.target)?evt.target:evt.srcElement;
var newText = elem.getAttribute('data-smile');
console.log('before', el.selectionStart, el.selectionEnd);
var start = el.selectionStart;
var end = el.selectionEnd;
var text = el.value;
var before = text.substring(0, start);
var after = text.substring(end, text.length);
el.value = (before + newText + after);
start = end = start + newText.length;
el.setSelectionRange(start, end);
console.log('after', el.selectionStart, el.selectionEnd);
}
}
};
<div>
<div id="chat-smiles-panel">
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/slightly-smiling-face_1f642.png" alt="smiley" data-smile=":smiley:" />
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/rolling-on-the-floor-laughing_1f923.png" alt="lol" data-smile=":lol:" />
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/smiling-face-with-halo_1f607.png" alt="angel" data-smile=":angel:" />
</div>
<textarea id="chat-textarea"></textarea>
</div>
每次在控制台日志中看到表情符号插入之前和之后的插入符号位置。
解决方案
我想你知道,el.value = (before + newText + after);
清除值并用新值替换它,将光标移回字段的开头。
我认为setSelectionRange
之后要跨浏览器工作,该领域必须再次获得关注。无论如何,这似乎是 Chrome 的情况,因为这 (with el.focus()
) 有效:
window.onload = function() {
var doc = window.document;
var smiles = doc.getElementById('chat-smiles-panel').getElementsByTagName('IMG');
var el = doc.getElementById('chat-textarea');
for (var i = 0; i < smiles.length; i++) {
smiles[i].onclick = function(e) {
var elem, evt = e?e:event;
elem = (evt.target)?evt.target:evt.srcElement;
var newText = elem.getAttribute('data-smile');
console.log('before', el.selectionStart, el.selectionEnd);
var start = el.selectionStart;
var end = el.selectionEnd;
var text = el.value;
var before = text.substring(0, start);
var after = text.substring(end, text.length);
el.value = (before + newText + after);
el.focus(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Added
start = end = start + newText.length;
el.setSelectionRange(start, end);
console.log('after', el.selectionStart, el.selectionEnd);
}
}
};
<div>
<div id="chat-smiles-panel">
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/slightly-smiling-face_1f642.png" alt="smiley" data-smile=":smiley:" />
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/rolling-on-the-floor-laughing_1f923.png" alt="lol" data-smile=":lol:" />
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/smiling-face-with-halo_1f607.png" alt="angel" data-smile=":angel:" />
</div>
<textarea id="chat-textarea"></textarea>
</div>
在您问过的评论中:
如果我不想将焦点放在 textarea 上,没有解决方案?我问是因为当文本区域获得焦点时,我试图让 UI 更友好地隐藏表情符号面板。因此,当脚本在插入表情符号后设置焦点时,表情符号面板会滑开,这并不好。
为了解决这个问题,我尝试在使用之前抓住活动元素focus
:
// Didn't work
var active = document.activeElement;
el.focus();
el.setSelectionRange(start, end);
if (active) {
active.focus();
}
当那不起作用时,我踢并使用el.blur()
了 ,它有效(尽管我不太喜欢它):
window.onload = function() {
var doc = window.document;
var smiles = doc.getElementById('chat-smiles-panel').getElementsByTagName('IMG');
var el = doc.getElementById('chat-textarea');
for (var i = 0; i < smiles.length; i++) {
smiles[i].onclick = function(e) {
var elem, evt = e?e:event;
elem = (evt.target)?evt.target:evt.srcElement;
var newText = elem.getAttribute('data-smile');
console.log('before', el.selectionStart, el.selectionEnd);
var start = el.selectionStart;
var end = el.selectionEnd;
var text = el.value;
var before = text.substring(0, start);
var after = text.substring(end, text.length);
el.value = (before + newText + after);
el.focus(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Added
start = end = start + newText.length;
el.setSelectionRange(start, end);
el.blur(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Added
console.log('after', el.selectionStart, el.selectionEnd);
}
}
};
<div>
<div id="chat-smiles-panel">
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/slightly-smiling-face_1f642.png" alt="smiley" data-smile=":smiley:" />
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/rolling-on-the-floor-laughing_1f923.png" alt="lol" data-smile=":lol:" />
<img width="20" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/apple/155/smiling-face-with-halo_1f607.png" alt="angel" data-smile=":angel:" />
</div>
<textarea id="chat-textarea">Testing 1 2 3</textarea>
</div>
我倾向于使表情符号面板在消失方面更聪明一些,例如从上次使用它时添加一秒钟的延迟,这样如果你想添加多个表情符号,你可以,但它会消失一秒钟在最后一个之后。
推荐阅读
- java - 有什么方法可以迭代 var in- System.out.println(here);?//(我尝试解释的内容是在我的代码之后编写的。)
- c++ - 如何在 C++ 中编写通用对象池
- r - 如何在 Kaggle 上的 Sberbank 俄罗斯住房市场数据集中估算缺失的“build_year”列?
- tibco - “TIBCO EMS TCPLink Reader”线程不断增加
- c++ - 等待服务器完成处理后如何接收“DONE”TCP数据包
- javascript - CSS将div添加到相对于父级定位的dom而没有其他内容跳转
- networking - 我可以使用反向代理直接连接数据库吗?
- ios - 使用 Apple 登录刷新令牌验证仅返回访问令牌
- macos - 每当我在 Mac 上打开 Hyper 时,我的屏幕都会黑屏几秒钟
- mysql - 节点mysql ER_PARSE_ERROR 1064