在textarea如何让使用js插入的文本能够被撤销?

问题描述

我想自己写一个在线编辑的工具,使用一个大的textarea作为编辑区域,我使用了如下的代码来完成单行或多行缩进,但是这样使用js插入的文本,并不能使用Ctrl+z来撤销操作,想问下有没有解决的办法,或者我的缩进思路从一开始就错了?

相关代码

  • 这是我自己写的一个DEMO,可以直接运行看到结果,大概思路是通过\n来判断行首的位置,并在其后插入两个空格作为缩进
<!--html-->
<textarea name="han" id="han" cols="30" rows="10"></textarea>
// javascript
let text = document.querySelector('textarea');

text.onkeydown = ()=>{
  if(event.key === "Tab"){
    event.preventDefault();
    let selectionStart = text.selectionStart;
    let selectionEnd = text.selectionEnd;   
    if(selectionEnd !== selectionStart){
      let textValue = text.value;
      let strBefore = textValue.slice(0,selectionStart);
      let lineStart = strBefore.lastIndexOf('\n') + 1;
      text.setRangeText('  ',lineStart,lineStart);
      strBetween = textValue.slice(selectionStart,selectionEnd);
      text.setRangeText(strBetween.replace('\n','\n  '));
      
    }
    else{
      text.setRangeText("  ");
      text.selectionStart += 2;
    }
  }
}

如果我描述的不够清楚,这有我写的一篇简书,里面写了我具体实现改功能的过程,希望有大佬能帮帮我
https://www.jianshu.com/p/273...

阅读 4.3k
2 个回答

明白你的意思,就是:使编辑器支持单行多行缩进,而且缩进操作可以通过 Ctrl + Z 撤销。

这种功能在 Chrome 的支持下写代码就跟玩似得,随便写一段都能用,但是要想支持 Firefox 和其他浏览器,那就不是玩了,而是要玩命了。

你要是做公共产品,建议你别自己折腾了,划不来,找个成熟的开源的编辑器直接用吧。

写了一段仅 Chrome 可用的代码给你折腾参考。

<script>

document.getElementById('han').addEventListener('keydown', function(event) {
    if (event.keyCode === 9 && window.chrome) {
        
        event.preventDefault();
    
        let tabstr = '  ';

        let start = this.selectionStart;
        let end = this.selectionEnd;  

        if (start === end) {
            
            // 没有选择文本,直接插入
            document.execCommand('insertText', false, tabstr);
            
        } else {
            
            let text = this.value;
            
            // tab 字符串长度,用来计算选择结束位置
            let tablen = tabstr.length;
            
            // 默认就插入一个 tab
            let insertstr = tabstr;
            
            // 默认就加一个 tab 长度
            let newend = end + tablen;
            
            // (如有换行)每一行前面都要插入一个 tablen
            // 同时也要加一个 tab 长度
            insertstr += text.slice(start, end).replace(/\n/g, function(){
                newend += tablen;
                return "\n" + tabstr;
            });
            
            // 插入加上 tab 的新字符串,这操作同时删除选中,相当于替换
            // 其实 Firefox 也有这个方法,但是表现怪异,几乎不能用
            document.execCommand('insertText', false, insertstr);

            // 选中加上 tab 的新字符串全部
            this.setSelectionRange(start, newend);
        }
    }
});

</script>

Stack Overflow有个答案
textarea下的撤销重做建议实现:
textarea所有的内容修改都通过新建event触发textinput事件实现

这时候就能用系统自带的 ctrl z 撤销 ctrl y 重做。

如果不是这样就要自己用栈保存结果来实现了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题