26

我正在通过设置contentEditable=true一个 div 来构建一个简单的文本编辑器(无论如何我认为 textarea 的行为方式相同)并且我在 tab 键上有一些问题。

我想要的是,当用户按下 tab 键时,焦点仍然在 div 上,并且一个 tab 字符被添加到文本中。

我通过preventDefault()在 keydown 上调用事件对象解决了问题的第一部分,现在 div 没有失去焦点,但我不知道为什么我不能插入字符。

tab char 的实体代码是,	但如果我尝试将此字符串添加到 innerHTML Firefox,则将其替换为一个简单的空格(而 不仅仅是一个空格)。我也试过,\t但结果是一样的。

所以我的问题是,如何在文本中插入制表符?

4

7 回答 7

34

我知道这有点老了,但这最终对我来说是最好的......

function onKeyDown(e) {
    if (e.keyCode === 9) { // tab key
        e.preventDefault();  // this will prevent us from tabbing out of the editor

        // now insert four non-breaking spaces for the tab key
        var editor = document.getElementById("editor");
        var doc = editor.ownerDocument.defaultView;
        var sel = doc.getSelection();
        var range = sel.getRangeAt(0);

        var tabNode = document.createTextNode("\u00a0\u00a0\u00a0\u00a0");
        range.insertNode(tabNode);

        range.setStartAfter(tabNode);
        range.setEndAfter(tabNode); 
        sel.removeAllRanges();
        sel.addRange(range);
    }
}
于 2015-08-20T21:09:55.243 回答
17

由于本应正确的答案对我不起作用,因此我想出了这个我认为对更多人有用的解决方案。

$(document).on('keyup', '.editor', function(e){
  //detect 'tab' key
  if(e.keyCode == 9){
    //add tab
    document.execCommand('insertHTML', false, '&#009');
    //prevent focusing on next element
    e.preventDefault()   
  }
});

该代码对我有用,但也要确保white-space:pre-wrap在您的 css 中包含该属性。希望这有帮助!

于 2016-03-23T02:30:15.583 回答
11

标签和空格在 html 中被折叠到一个空格,除非在<pre>标签中或white-space: pre在其样式中

于 2010-02-10T14:43:31.350 回答
10

我使用这个解决方案:

$('[contenteditable]').on('keydown', function(e){
    if(e.keyCode == 9){
        e.preventDefault();
        document.execCommand('insertHTML', false, '&#009');
    }
}).css('white-space', 'pre-wrap');

使用可编辑代码时,<pre>元素不需要最后添加的 css。keyupvskeydown和 e.preventDefault() 的位置在浏览器中可能不同。

注意:我认为应该避免绑定键事件或整个文档中的任何内容。我在 Safari / iOS 桌面浏览器中遇到了一些奇怪的问题,这些浏览器带有 contenteditable 元素和冒泡事件。

于 2017-09-26T03:09:34.833 回答
8

您只看到一个简单空格的原因是因为空白字符序列(不间断空格除外)在 div 中被视为单个空格字符。如果您希望制表符以您期望的方式显示,您需要将它放在像<pre>在源 HTML 中一样呈现空白的元素内,或者放在white-space: pre通过 CSS 设置的元素内。

于 2010-02-10T14:42:40.173 回答
8

您可以使用 white-space=pre 和内容选项卡插入跨度。最好使用这样的范围:

// adapted from http://stackoverflow.com/a/25943182/460084
function insertTab() {
  if (!window.getSelection) return;
  const sel = window.getSelection();
  if (!sel.rangeCount) return;
  const range = sel.getRangeAt(0);
  range.collapse(true);
  const span = document.createElement('span');
  span.appendChild(document.createTextNode('\t'));
  span.style.whiteSpace = 'pre';
  range.insertNode(span);
  // Move the caret immediately after the inserted span
  range.setStartAfter(span);
  range.collapse(true);
  sel.removeAllRanges();
  sel.addRange(range);
}

$(document).on('keydown', '.editor', function(e) {
  if (e.keyCode == 9) {
    insertTab();
    e.preventDefault()
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable=true style="border: solid" class='editor'></div>

于 2017-04-04T22:35:47.757 回答
4

下面是一个工作示例,它禁止在contenteditable已经具有焦点的情况下单击Tab时失去焦点,而是插入一个制表符

var elm = document.querySelector('[contenteditable]')

// when the contenteditable gets focused, start listening to key presses
elm.addEventListener('focus', onFocus)

// when the contenteditable looses focus, remove "keydown" event listener
elm.addEventListener('blur', onFocus)

function onFocus(){
  window.addEventListener('keydown', onKeyDown)
}

function onBlur(){
  window.removeEventListener('keydown', onKeyDown)
}

function onKeyDown(e) {
   if (e.keyCode != 9) return // tab key
    
    e.preventDefault();  // prevent default behaviour, which is "blur"

    var sel = document.getSelection();
    var range = sel.getRangeAt(0);

    var tabNodeValue = '\u0009' // with 4 spaces: Array(4).join('\u00a0')
    var tabNode = document.createTextNode(tabNodeValue);

    range.insertNode(tabNode);

    range.setStartAfter(tabNode);
    range.setEndAfter(tabNode); 
}
[contenteditable]{
  min-height: 150px;
  border: 1px solid black;
  padding: 5px;
  white-space: pre;  /* <-- needed in order to render "tab" unicode */
}
<div contenteditable></div>

于 2020-08-07T11:38:51.100 回答