首页 > 解决方案 > 为什么 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>

每次在控制台日志中看到表情符号插入之前和之后的插入符号位置。

标签: javascript

解决方案


我想你知道,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>

我倾向于使表情符号面板在消失方面更聪明一些,例如从上次使用它时添加一秒钟的延迟,这样如果你想添加多个表情符号,你可以,但它会消失一秒钟在最后一个之后。


推荐阅读