使用JavaScript语法高亮显示

问题描述:

我想用JavaScript做一个简单的语法高亮显示,但我总是会遇到同样的问题。该程序的工作原理如下:当用户输入(不带shift键)时,程序将用另一个关键字var用红色代替关键字var(这仍然非常基本)。问题在于,无论何时按下回车键,文本都会突出显示,但光标会返回到第一行的第一个单词。你如何看待我可以防止这种情况发生?使用JavaScript语法高亮显示

<div class="container"> 
    <pre class="text"><code contenteditable="true" id="format"> 
    </code></pre> 
</div> 

JS

var editor = document.getElementById('format'); 
var npatt =/*var +/igm 
editor.addEventListener('keyup', highlight); 

function highlight(e){ 
    var content = editor.innerHTML; 
    if(e.which === 13 && e.shiftKey===false){ 
     editor.innerHTML = content.replace(npatt, '<span style="color:red">var</span>&nbsp;'); 
     console.log(editor.innerHTML); 
    } 
} 
+0

也许光标的移动,因为现有的内容由语法高亮显示的内容被完全取代,所以光标位置是没有意义的,并恢复为默认的位置? – Ryan

+0

你可以发布JSfiddle或代码片段吗? –

+0

是的,但我该如何解决这个问题?,我的意思是说,当我点击输入时,替换的文本应该在第一行(或任何行)和下一行的光标? – Noctisdark

移动光标到一个contenteditable元件的端部可以根据在所述this answer方法来完成。该方法使用window.getSelection() method来查找光标位置。

我对代码做了一些更改。

  1. 增加了test check,看看正则表达式甚至与内容相匹配,以避免调用replace和每设置editor.innerHTML输入击键的原代码一样。
  2. 添加了对cursorManager.setEndOfContenteditable方法的调用(根据上面提及的答案),将光标重置为replace操作后的编辑器末尾。

这里是更新的代码。

var editor = document.getElementById('format'); 
var npatt =/*var +/igm; 

editor.addEventListener('keyup', highlight); 

function highlight(e){ 
    var content = editor.innerHTML; 

    if(e.which === 13 && e.shiftKey === false && npatt.test(content)) { 
     editor.innerHTML = content.replace(npatt, '<span style="color:red">var</span>&nbsp;'); 
     cursorManager.setEndOfContenteditable(editor); 
    } 
} 

这里是一个工作示例。

var editor = document.getElementById('format'); 
 
var npatt =/*var +/igm; 
 

 
editor.addEventListener('keyup', highlight); 
 

 
function highlight(e){ 
 
    var content = editor.innerHTML; 
 
    
 
    if(e.which === 13 && e.shiftKey === false && npatt.test(content)) { 
 
     editor.innerHTML = content.replace(npatt, '<span style="color:red">var</span>&nbsp;'); 
 
     cursorManager.setEndOfContenteditable(editor); 
 
    } 
 
} 
 

 
//Code to set the cursor position modified from this answer: https://stackoverflow.com/a/19588665/830125 
 
//Namespace management idea from http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/ 
 
(function(cursorManager) { 
 

 
    //From: http://www.w3.org/TR/html-markup/syntax.html#syntax-elements 
 
    var voidNodeTags = ['AREA', 'BASE', 'BR', 'COL', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'MENUITEM', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR', 'BASEFONT', 'BGSOUND', 'FRAME', 'ISINDEX']; 
 

 
    //From: https://stackoverflow.com/questions/237104/array-containsobj-in-javascript 
 
    Array.prototype.contains = function(obj) { 
 
     var i = this.length; 
 
     while (i--) { 
 
      if (this[i] === obj) { 
 
       return true; 
 
      } 
 
     } 
 
     return false; 
 
    } 
 

 
    //Basic idea from: https://stackoverflow.com/questions/19790442/test-if-an-element-can-contain-text 
 
    function canContainText(node) { 
 
     if(node.nodeType == 1) { //is an element node 
 
      return !voidNodeTags.contains(node.nodeName); 
 
     } else { //is not an element node 
 
      return false; 
 
     } 
 
    }; 
 

 
    function getLastChildElement(el){ 
 
     var lc = el.lastChild; 
 
     while(lc && lc.nodeType != 1) { 
 
      if(lc.previousSibling) 
 
       lc = lc.previousSibling; 
 
      else 
 
       break; 
 
     } 
 
     return lc; 
 
    } 
 

 
    //Based on Nico Burns's answer 
 
    cursorManager.setEndOfContenteditable = function(contentEditableElement) 
 
    { 
 
     var range,selection; 
 
     if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+ 
 
     {  
 
      range = document.createRange();//Create a range (a range is a like the selection but invisible) 
 
      range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range 
 
      range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start 
 
      selection = window.getSelection();//get the selection object (allows you to change selection) 
 
      selection.removeAllRanges();//remove any selections already made 
 
      selection.addRange(range);//make the range you have just created the visible selection 
 
     } 
 
     else if(document.selection)//IE 8 and lower 
 
     { 
 
      range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible) 
 
      range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range 
 
      range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start 
 
      range.select();//Select the range (make it the visible selection 
 
     } 
 
    } 
 

 
}(window.cursorManager = window.cursorManager || {}));
<div class="container"> 
 
    <pre class="text"><code contenteditable="true" id="format"> 
 
    </code></pre> 
 
</div>

+0

谢谢,谢谢你谢谢!!,你救了我的命,我从来没有想过这可以完成!谢谢 – Noctisdark