为什么文本区域中的选择范围会重置为0?

时间:2019-02-24 16:53:05

标签: javascript

我有一些IMG表情符号,可以将它们作为字符串表示形式插入到textarea中。下面的脚本必须位于插入记号的位置,并将其插入到正确的位置,但有时会触发错误,并将选择范围重置为0。

您可以看到它在玩耍,例如单击微笑并在文本区域内单击。在文本区域内容的末尾设置了插入符号后,我已立即重置为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>

每次在控制台日志中都可以看到插入表情符号前后的牙齿位置。

1 个答案:

答案 0 :(得分:3)

我想您知道,el.value = (before + newText + after);会擦除该值并将其替换为新值,将光标移回该字段的开头。

我认为,为了使setSelectionRange能够跨浏览器工作,该领域必须再次获得关注。无论如何,Chrome似乎都是这种情况,因为(使用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>

我倾向于使表情面板在消失时更智能,例如,从上次使用开始增加一秒钟的延迟,这样,如果您想添加多个表情,可以,但是可以在最后一个之后第二秒消失。