如何使元素textarea自动着色子串?

时间:2017-02-03 14:13:47

标签: javascript html css

<textarea>处写一个red的最佳方法是什么?它会自动为红色这个词I ate tha'red-meat着色?

即使它没有被空格包围,它也应该着色 因此,例如,它仍然适用于文字reddit和单词red

This是查找包含body { margin: 0; } textarea { background-color: GhostWhite; border: 0; height: 100%; outline: none; resize: none; width: 100%; }字词的理想场所。

我有以下代码:

<textarea spellcheck="false"></textarea>
outcum

4 个答案:

答案 0 :(得分:1)

所以你可以使用一个contenteditable div,匹配任何前面没有>的红色,然后将红色替换为:"$1<span class='specialColor'>red</span>&zwnj;"零宽度的非连接字符end用作跨度的分隔符。

document.getElementById('foo').addEventListener('input', function(e) {
  var re = /([^\>])red/;
  var split = this.innerHTML.replace(re, "$1<span class='specialColor'>red</span>&zwnj;");
  this.innerHTML = split;
  placeCaretAtEnd(this);
})

function placeCaretAtEnd(el) {
  el.focus();
  if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") {
    var range = document.createRange();
    range.selectNodeContents(el);
    range.collapse(false);
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
  } else if (typeof document.body.createTextRange != "undefined") {
    var textRange = document.body.createTextRange();
    textRange.moveToElementText(el);
    textRange.collapse(false);
    textRange.select();
  }
}
body {
  margin: 0;
}
textarea {
  background-color: GhostWhite;
  border: 0;
  height: 100%;
  outline: none;
  resize: none;
  width: 100%;
}

.specialColor {
  color:red;
}
<div id="foo" contenteditable spellcheck="false"></div>

声明:

placeCaretAtEnd()方法取自此SO答案:contenteditable, set caret at the end of the text (cross-browser)

答案 1 :(得分:1)

您无法使用textarea执行此操作,而是使用contenteditable范围(建议使用span以避免输入<时出现问题)并换色通过使用span来子串。

&#13;
&#13;
var div = document.getElementById('div');

div.addEventListener('input', function() {
    // get the current position
    var pos = getCaretCharacterOffsetWithin(this);
  // get all word in the content  
  this.innerHTML = this.innerText.replace(/\w+/g, function(m) {
    // create a temporary span element
    var temp = document.createElement('span');
    // set current word as color
    temp.style.color = m;
    // check color is valid by rechecking the proeprty
    if (temp.style.color) {
      // if valid color then replace with temp elements html after setting content
      temp.innerHTML = m;
      return temp.outerHTML;
    }
    // else return the word itself
    return m;
  })
  // set caret position
  setCaretPosition(this, pos);
})



// following code is copied from following question
// https://stackoverflow.com/questions/26139475/restore-cursor-position-after-changing-contenteditable

function getCaretCharacterOffsetWithin(element) {
  var caretOffset = 0;
  var doc = element.ownerDocument || element.document;
  var win = doc.defaultView || doc.parentWindow;
  var sel;
  if (typeof win.getSelection != "undefined") {
    sel = win.getSelection();
    if (sel.rangeCount > 0) {
      var range = win.getSelection().getRangeAt(0);
      var preCaretRange = range.cloneRange();
      preCaretRange.selectNodeContents(element);
      preCaretRange.setEnd(range.endContainer, range.endOffset);
      caretOffset = preCaretRange.toString().length;
    }
  } else if ((sel = doc.selection) && sel.type != "Control") {
    var textRange = sel.createRange();
    var preCaretTextRange = doc.body.createTextRange();
    preCaretTextRange.moveToElementText(element);
    preCaretTextRange.setEndPoint("EndToEnd", textRange);
    caretOffset = preCaretTextRange.text.length;
  }
  return caretOffset;
}

function setCaretPosition(element, offset) {
  var range = document.createRange();
  var sel = window.getSelection();

  //select appropriate node
  var currentNode = null;
  var previousNode = null;

  for (var i = 0; i < element.childNodes.length; i++) {
    //save previous node
    previousNode = currentNode;

    //get current node
    currentNode = element.childNodes[i];
    //if we get span or something else then we should get child node
    while (currentNode.childNodes.length > 0) {
      currentNode = currentNode.childNodes[0];
    }

    //calc offset in current node
    if (previousNode != null) {
      offset -= previousNode.length;
    }
    //check whether current node has enough length
    if (offset <= currentNode.length) {
      break;
    }
  }
  //move caret to specified offset
  if (currentNode != null) {
    range.setStart(currentNode, offset);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
  }
}
&#13;
<span contenteditable="true" id="div">sss</span>
&#13;
&#13;
&#13;

注意:对于位置保留代码,请复制自:Restore cursor position after changing contenteditable

更新:如果您只想在任何字词中替换red,那么您可以这样做:

&#13;
&#13;
var div = document.getElementById('div');

div.addEventListener('input', function() {
  var pos = getCaretCharacterOffsetWithin(this);
  // get all red subtring and wrap it with span
  this.innerHTML = this.innerText.replace(/red/g, '<span style="color:red">$&</span>')
  setCaretPosition(this, pos);
})



// following code is copied from following question
// https://stackoverflow.com/questions/26139475/restore-cursor-position-after-changing-contenteditable

function getCaretCharacterOffsetWithin(element) {
  var caretOffset = 0;
  var doc = element.ownerDocument || element.document;
  var win = doc.defaultView || doc.parentWindow;
  var sel;
  if (typeof win.getSelection != "undefined") {
    sel = win.getSelection();
    if (sel.rangeCount > 0) {
      var range = win.getSelection().getRangeAt(0);
      var preCaretRange = range.cloneRange();
      preCaretRange.selectNodeContents(element);
      preCaretRange.setEnd(range.endContainer, range.endOffset);
      caretOffset = preCaretRange.toString().length;
    }
  } else if ((sel = doc.selection) && sel.type != "Control") {
    var textRange = sel.createRange();
    var preCaretTextRange = doc.body.createTextRange();
    preCaretTextRange.moveToElementText(element);
    preCaretTextRange.setEndPoint("EndToEnd", textRange);
    caretOffset = preCaretTextRange.text.length;
  }
  return caretOffset;
}

function setCaretPosition(element, offset) {
  var range = document.createRange();
  var sel = window.getSelection();

  //select appropriate node
  var currentNode = null;
  var previousNode = null;

  for (var i = 0; i < element.childNodes.length; i++) {
    //save previous node
    previousNode = currentNode;

    //get current node
    currentNode = element.childNodes[i];
    //if we get span or something else then we should get child node
    while (currentNode.childNodes.length > 0) {
      currentNode = currentNode.childNodes[0];
    }

    //calc offset in current node
    if (previousNode != null) {
      offset -= previousNode.length;
    }
    //check whether current node has enough length
    if (offset <= currentNode.length) {
      break;
    }
  }
  //move caret to specified offset
  if (currentNode != null) {
    range.setStart(currentNode, offset);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
  }
}
&#13;
<span contenteditable="true" id="div" style="width:100%;display:block">sss</span>
&#13;
&#13;
&#13;

注意:此解决方案存在一些与换行相关的问题,因为内容是HTML并且换行没有任何意义。

答案 2 :(得分:0)

您无法在可编辑输入区域(如inputtextarea)内的文本中添加部分样式。它被视为单个文本块,只能作为一个整体设置。

但是,可以通过巧妙定位样式化的span元素来模拟所需的效果。

有一个这样的项目可以随时随地提供文字突出显示。检查出来:Code Mirror Project

我在我的一个个人项目中使用过codemirror。你也应该看看它。 See the editable pane on the left

答案 3 :(得分:0)

我唯一不满意的是它如何处理换行符和标签。 它比仅替换红色更复杂一点,但这样你可以突出显示任何颜色的任何单词,甚至可能在同一元素上混合其中的几个,所以使用的函数是可重用的。

<html>
<head>
    <style>
    #myTextarea {
        border: 1px solid black;
        border-radius: 5px;
        min-height: 50px;
        width: 50%;
    }
    .hl-red {
        color: red;
    }
    </style>
</head>
<body>
<div id="myTextarea" contenteditable>Test string</div>
<script>
var createHighlighter = function createHighlighter( word ) {
    // Let's create a reusable function that can highlight any word.
    // You call this function providing the word you want highlighted.
    // Then this returns a function that will insert some html spans around each instance of the word.
    // You can the call the returned function with any string to get the string saturated with the span tags.
    return function highlight( str ) {
        // We split on the word we want to highlight, so our array contains all the non-highlighted chunks.
        // Since we can call the function multiple times in a row, we will usually want to remove the previous highlights, so we don't double-highlight it.
        // This can be easily done with a simple global replace regex.
        var chunks;
        if (str === '<br>') return '';
        else {
            chunks = str.replace(/\<span\sclass="hl-red"\>/g, '').replace(/\<\/span\>/g, '').split(word);
            // Then we add the non-highlighted text + the <span> + the highlighted word.
            return chunks.reduce(function( html, chunk, index ) {
                html += chunk;
                // Add the highlighted word, except for the last chunk, since that's just the end of the string.
                if ((index + 1) !== chunks.length) html += '<span class="hl-red">' + word + '</span>';
                return html;
            }, '');
        }
    };
};

var wordToHighlight = 'red';

var highlightRed = createHighlighter( wordToHighlight );

var highlightArea = function highlightArea( event ) {
    event.target.innerHTML = highlightRed( event.target.innerHTML );
};

document.querySelector('#myTextarea').addEventListener('keyup', highlightArea);

</script>
</body>
</html>