【问题标题】:Change color of specific words in textarea更改文本区域中特定单词的颜色
【发布时间】:2016-05-10 12:49:42
【问题描述】:

我正在构建一个 Sql 查询生成器,并希望在用户键入诸如 SELECT、FROM、WHERE 之类的单词时更改文本区域中单词的文本颜色。

我已经搜索了一些,并且超出了这个范围 (https://jsfiddle.net/qcykvr8j/2/),很遗憾我没有再进一步了。

示例代码

HTML:

<textarea name="query_field_one" id="query_field_one" onkeyup="checkName(this)"></textarea>

JS:

    function checkName(el)
    {
    if (el.value == "SELECT" || 
    el.value == "FROM" || 
    el.value == "WHERE" || 
    el.value == "LIKE" || 
    el.value == "BETWEEN" || 
    el.value == "NOT LIKE" || 
    el.value == "FALSE" || 
    el.value == "NULL" || 
    el.value == "TRUE" || 
    el.value == "NOT IN")
    {
      el.style.color='orange'

    }
    else {
      el.style.color='#FFF'

    }
  }

JSFiddle:

https://jsfiddle.net/qcykvr8j/2/

但是当我进一步输入时,这个例子会删除颜色。

我想要的是这个:

我已经尝试过将 Keyup 与 jQuery 中的 Contains 结合使用,但效果并不明显。

键入:https://api.jquery.com/keyup/

包含:https://api.jquery.com/contains-selector/

我希望有人可以通过示例或网站帮助我找到更多信息。

问候,詹斯

【问题讨论】:

  • 您正在更改元素颜色el.style.color 这就是为什么通过它不起作用。你需要使用 CKEditor 类型的东西。手动执行此操作需要使用自定义样式标签将单词处理为 spans 或 div
  • 是的,我知道为什么该示例不起作用。该示例仅用于提供更多信息。我认为使用 Jquery 可能很容易,但我认为它确实太难了。
  • 您是否考虑过使用不同的样式类,然后搜索/替换“SELECT”替换为“SELECT”。
  • 您每次都检查文本区域的整个值。仅当 textarea 的内容仅包含其中一个单词而没有其他单词时,您的代码才有效。您可以使用 jQuery .split() 将每个单词抓取到一个数组中并进行比较;可能是更好的方法,只是想到的第一件事。
  • 是的,只是它对我来说似乎不是很有用..

标签: javascript jquery html onkeyup


【解决方案1】:

您无法更改&lt;textarea&gt; 中单词的颜色,但您可以使用contenteditable 属性使&lt;div&gt;、&lt;span&gt; 或&lt;p&gt; 看起来像&lt;textarea&gt;。

为此,您可以使用 JavaScript 插件,但如果您想创建一个新插件,下面的代码可能会对您有所帮助。

为此,您需要获取文本中的任何单词。然后检查它是否是 SQL 关键字。

// SQL keywords
var keywords = ["SELECT","FROM","WHERE","LIKE","BETWEEN","NOT LIKE","FALSE","NULL","FROM","TRUE","NOT IN"];
// Keyup event
$("#editor").on("keyup", function(e){
  // Space key pressed
  if (e.keyCode == 32){
    var newHTML = "";
    // Loop through words
    $(this).text().replace(/[\s]+/g, " ").trim().split(" ").forEach(function(val){
      // If word is statement
      if (keywords.indexOf(val.trim().toUpperCase()) > -1)
        newHTML += "<span class='statement'>" + val + "&nbsp;</span>";
      else
        newHTML += "<span class='other'>" + val + "&nbsp;</span>"; 
    });
    $(this).html(newHTML);

    // Set cursor postion to end of text
    var child = $(this).children();
    var range = document.createRange();
    var sel = window.getSelection();
    range.setStart(child[child.length-1], 1);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
    this.focus();
  }
});
#editor {
    width: 400px;
    height: 100px;
    padding: 10px;
    background-color: #444;
    color: white;
    font-size: 14px;
    font-family: monospace;
}
.statement {
    color: orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="editor" contenteditable="true"></div>

【讨论】:

  • 哇!这实际上是一个很好的解决方案,它在发布数据时有点困难,但我会用 Ajax 解决这个问题,我可以用 strip_tag() 删除 html 标签;感谢您的回复!
  • @VenkatSoma 不,输入和文本区域不能有子元素和内容样式。目标元素应该接受子元素。
  • 这段代码似乎删除了换行符,是否有一个调整可以让它保留换行符。我将它用于类似的设置,当我按下回车键时,它会删除换行符并将其全部放回一行。
  • @Mohammad 您的解决方案很棒!但它似乎并没有像您在切换案例中提到的那样突出显示“不在”之类的多个词。知道为什么吗?
  • @manjesh23 删除代码的 keyup 事件处理程序并在您的函数之后运行它。
【解决方案2】:

JS FIDDLE CODE

HTML-

<div id="board" class="original" contenteditable="true"></div>
<div id="dummy" class="original"></div>

CSS-

.original {
   position:absolute;width: 50%; margin: 0 auto; padding: 1em;background: #fff;height:100px;margin:2px;border:1px solid black;color:#fff;overflow:auto;
}

#dummy{
  color:black;
}
#board{
  z-index:11;background:transparent;color:transparent;caret-color: black;
}
.original span.highlighted {
    color:red;
}

JAVASCRIPT -

var highLightedWord = ["select","insert","update","from","where"];
var regexFromMyArray = new RegExp(highLightedWord.join("|"), 'ig');
$('#board').keyup(function(event){
 document.getElementById('dummy').innerHTML = $('#board').html().replace(regexFromMyArray,function(str){
 return '<span class="highlighted">'+str+'</span>'
 })
})
var target = $("#dummy");
  $("#board").scroll(function() {
    target.prop("scrollTop", this.scrollTop)
          .prop("scrollLeft", this.scrollLeft);
  });

【讨论】:

  • 不错的解决方案!这比其他的要好得多。
【解决方案3】:

使用 Vanilla JS,您可以这样做:

    // SQL keywords
    var keywords = ["SELECT", "FROM", "WHERE", "LIKE", "BETWEEN", "UNION", "FALSE", "NULL", "FROM", "TRUE", "NOT", "ORDER", "GROUP", "BY", "NOT", "IN"];
    // Keyup event
    document.querySelector('#editor').addEventListener('keyup', e => {
    // Space key pressed
    if (e.keyCode == 32) {
        var newHTML = "";
        // Loop through words
        str = e.target.innerText;
        chunks = str
          .split(new RegExp(
            keywords
              .map(w => `(${w})`)
              .join('|'), 'i'))
          .filter(Boolean),
        markup = chunks.reduce((acc, chunk) => {
          acc += keywords.includes(chunk.toUpperCase()) ?
          `<span class="statement">${chunk}</span>` :
          `<span class='other'>${chunk}</span>`
          return acc
        }, '')      
        e.target.innerHTML = markup;

        // Set cursor postion to end of text
        //    document.querySelector('#editor').focus()
        var child = e.target.children;
        var range = document.createRange();
        var sel = window.getSelection();
        range.setStart(child[child.length - 1], 1);
        range.collapse(true);
        sel.removeAllRanges();
        sel.addRange(range);
        this.focus();
            
        }
    });
        #editor {
            width: 400px;
            height: 100px;
            padding: 10px;
            background-color: #444;
            color: white;
            font-size: 14px;
            font-family: monospace;
        }
        .statement {
            color: orange;
        }
&lt;div id="editor" contenteditable="true"&gt;&lt;/div&gt;

【讨论】:

  • 我很喜欢这段代码,可以去掉空格键按下看看实际效果吗?意思是,我有一个 div 标签,其中数据是从另一个函数自动填充的。想用你的 JS 代码来高亮显示。
【解决方案4】:

我无法对插入符号做些什么,所以我借用了其他人的工作,它使代码有点庞大。我不知道它有多快,但效果很好:T

我借用的代码:

https://jsfiddle.net/nrx9yvw9/5/

Get a range's start and end offset's relative to its parent container

你可以在没有 jquery 的情况下运行:

 //(sorry for the grammer mistakes)

/*Caret function sources: https://jsfiddle.net/nrx9yvw9/5/ && https://stackoverflow.com/questions/4811822/get-a-ranges-start-and-end-offsets-relative-to-its-parent-container/4812022#4812022*/
function createRange(e,t,n){if(n||((n=document.createRange()).selectNode(e),n.setStart(e,0)),0===t.count)n.setEnd(e,t.count);else if(e&&t.count>0)if(e.nodeType===Node.TEXT_NODE)e.textContent.length<t.count?t.count-=e.textContent.length:(n.setEnd(e,t.count),t.count=0);else for(var o=0;o<e.childNodes.length&&(n=createRange(e.childNodes[o],t,n),0!==t.count);o++);return n}function getCurrentCaretPosition(e){var t,n=0,o=e.ownerDocument||e.document,a=o.defaultView||o.parentWindow;if(void 0!==a.getSelection){if((t=a.getSelection()).rangeCount>0){var r=a.getSelection().getRangeAt(0),c=r.cloneRange();c.selectNodeContents(e),c.setEnd(r.endContainer,r.endOffset),n=c.toString().length}}else if((t=o.selection)&&"Control"!=t.type){var i=t.createRange(),g=o.body.createTextRange();g.moveToElementText(e),g.setEndPoint("EndToEnd",i),n=g.text.length}return n}function setCurrentCaretPosition(e,t){if(t>=0){var n=window.getSelection();range=createRange(e,{count:t}),range&&(range.collapse(!1),n.removeAllRanges(),n.addRange(range))}}
/*Caret functions end*/


/*
 * -> required | [...,...] -> example | {...} -> value type | || -> or 

  id:         Position of words for where they should be colored  [undefined,0,1,...] {int||string}
  color:      Color for words  [aqua,rgba(0,255,0,1),#ff25d0] {string}
  fontStyle:  Font style for words  [italic,oblique,normal] {string}
  decoration: Text decoration for words  [underlined,blink,dashes] {string}
* words:      Words that should be colored  {array}
*/
var keywords = [
   {
      color: "orange",
      words: [
         "SELECT",
         "FROM",
         "WHERE",
         "LIKE",
         "BETWEEN",
         "NOT",
         "FALSE",
         "NULL",
         "TRUE",
         "IN",
      ],
   },
   {
      id: 0,
      color: "red",
      fontStyle: "italic",
      decoration: "underline",
      words: ["TEST"],
   },
];

//defining node object as "editor"
var editor = document.getElementById("editor");

//listening editor for keyup event
editor.addEventListener("keyup", function (e) {
   // if ctrl or alt or shift or backspace and keyname's length is not 1, don't check
   if( e.ctrlKey || e.altKey || ( e.key.length - 1 && e.key != "Backspace" ) || ( e.shiftKey && e.char ) ) return;

   //getting caret position for applying it in the end, because after checking and coloring done; it's gonna be at the beginning.
   pos = getCurrentCaretPosition(this);

   
   text = this.innerText; //getting input's just text value
   words = text.split(/\s/gm); //splitting it from all whitespace characters

   for (var i = 0; i < keywords.length; i++)
      for (var n = 0; n < words.length; n++) {
         //looks for is word in our "keywords"' object and check's position if it's id entered
         if (keywords[i].words.indexOf(words[n].toUpperCase().trim()) > -1 && (keywords[i].id >= 0 ? keywords[i].id == n : true) )
            //applys options to word
            words[n] = `<span style="color:${ keywords[i].color ?? "white" };font-style:${ keywords[i].fontStyle ?? "normal" };text-decoration:${ keywords[i].decoration ?? "normal" }">${words[n]}</span>`;
      }

   //joining array elements with whitespace caracter and apply it to input
   this.innerHTML = words.join("&nbsp;");
   //restoring caret position
   setCurrentCaretPosition(this, pos);
});
    #editor {
   width: 400px;
   height: 100px;
   padding: 10px;
   background-color: #444;
   color: white;
   font-size: 14px;
   font-family: monospace;
   font-weight: normal;
   caret-color: white;
}
&lt;div id="editor" spellcheck="false" contenteditable="true"&gt;&lt;/div&gt;

【讨论】:

  • 我的意思是......它有效!尽管我确实建议格式化您的代码,以便其他人更容易阅读。在线工具,如 prettier playground 帮助。
  • @MingyeWang 哦,我真的忘记格式化了。。谢谢你的建议。
【解决方案5】:

这不是这个问题的答案,但它回答了标题问题,当您在谷歌搜索有关突出显示文本区域中的单词时会发现该问题。

可以使用内置 API setSelectionRange 函数和 ::selection css 选择器在 textarea 元素中进行彩色选择。

注意,它一次只支持一个文本选择,并且只支持直到文本区域获得焦点。

  const input = document
        .getElementById( 'text-box' );
  
  var i, l;

  input.focus();
  input.value = input.value.trim();
  
  i = input.value .indexOf( 'programming' );
  l = ( 'programming' ).length;
  
  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange
  
  input
  .setSelectionRange( i, l + i );
::-moz-selection {
  background-color: yellow;
  color: red;
}
::selection {
  background-color: yellow;
  color: red;
}
<textarea id="text-box" size="40">
  I like programming with JavaScript!
</textarea>

【讨论】:

    【解决方案6】:

    // SQL keywords
    var keywords = ["SELECT","FROM","WHERE","LIKE","BETWEEN","NOT LIKE","FALSE","NULL","FROM","TRUE","NOT IN"];
    // Keyup event
    $("#editor").on("keyup", function(e){
      // Space key pressed
      if (e.keyCode == 32){
        var newHTML = "";
        // Loop through words
        $(this).text().replace(/[\s]+/g, " ").trim().split(" ").forEach(function(val){
          // If word is statement
          if (keywords.indexOf(val.trim().toUpperCase()) > -1)
            newHTML += "<span class='statement'>" + val + "&nbsp;</span>";
          else
            newHTML += "<span class='other'>" + val + "&nbsp;</span>"; 
        });
        $(this).html(newHTML);
    
        // Set cursor postion to end of text
        var child = $(this).children();
        var range = document.createRange();
        var sel = window.getSelection();
        range.setStart(child[child.length-1], 1);
        range.collapse(true);
        sel.removeAllRanges();
        sel.addRange(range);
        this.focus();
      }
    });
    #editor {
        width: 400px;
        height: 100px;
        padding: 10px;
        background-color: #444;
        color: white;
        font-size: 14px;
        font-family: monospace;
    }
    .statement {
        color: orange;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="editor" contenteditable="true"></div>

    【讨论】:

      【解决方案7】:

      我发现了另一个独特的解决方案,与其他解决方案相比非常简单。基本上,这个想法是将一些突出显示的代码放在 textarea 后面,并使 textarea 除了插入符号之外不可见。

      我使用https://github.com/jgnewman/custom-syntax-highlighter 来定义我自己的语言。你可以使用任何你想要的东西。

      这里描述了这个想法,但我添加了一个最小的示例:https://css-tricks.com/creating-an-editable-textarea-that-supports-syntax-highlighted-code/ 你仍然应该阅读那里来解决滚动问题

      尝试在下面输入以下内容:callFunction('with string')

      //on reload the textarea will still contain text. We have to put that into the code element and format the text
      function init() {
          update(document.getElementById('editing').value);
      }
      window.onload = init;
      
      function update(text) {
      
        //put textarea content into code tags
        let result_element = document.querySelector('#highlighting-content');
        result_element.innerText = text;
      
        // Syntax Highlight define your own Regex. Names will be css classes to stile
        highlight({
          patterns: [{
              name: 'string',
              match: /^(\'[^\'\n]*\')/,
            },
            {
              name: 'fn-call',
              match: [/^([A-z_]+)\(/, '', '('],
            },
          ],
        });
      }
      html,
      body {
          margin: 0px;
          padding: 0px;
          height: 100%;
      }
      
      .container {
          display: grid;
          height: 100%;
          margin: 0px;
          padding: 0px;
      }
      
      pre,
      code {
          white-space: pre-line;
          /*Remove indetend on first line*/
      }
      
      #editing,
      #highlighting {
          /*position above each other*/
          grid-column: 1;
          grid-row: 1;
          margin: 0px;
          padding: 0px;
          /*make sure to apply text styling to both*/
          font-size: 15pt;
          font-family: monospace;
          line-height: 20pt;
      }
      
      #editing {
          color: transparent;
          background: transparent;
          caret-color: white;
          color: transparent;
      }
      
      
      /*syntax highlighting class names defined in js code*/
      
      .fn-call {
          color: red;
      }
      
      .string {
          color: blue;
      }
      <!DOCTYPE html>
      <html lang="en">
      
      <head>
        <script src="https://unpkg.com/custom-syntax-highlighter@latest/bin/index.js"></script>
        <script>
          var highlight = window.csHighlight; //need to initialize the library
        </script>
      
      </head>
      
      <body>
      
        <!--Container is display grid to position textarea and code above each other-->
        <div class="container">
          <!--the code element that will be highlighted-->
          <pre id="highlighting" aria-hidden="true">
            <code id="highlighting-content">
            </code>
          </pre>
      
          <!--make sure the textarea is in front and can be interacted with. disable spell check-->
          <textarea id="editing" spellcheck="false" oninput="update(this.value);"></textarea>
        </div>
      
      </body>
      
      </html>

      祝你有美好的一天

      【讨论】:

        【解决方案8】:

        您可以使用此代码

        <code contenteditable="true">
          <span style="color: orange">SELECT</span> *
          <span style="color: orange">FROM</span>
           TABLE
          <span style="color: orange">WHERE</span>
          id = 2
        </code>
        

        【讨论】:

          猜你喜欢
          • 2012-06-16
          • 2013-10-14
          • 1970-01-01
          • 1970-01-01
          • 2011-06-05
          • 1970-01-01
          • 1970-01-01
          • 2021-12-01
          • 2013-11-03
          相关资源
          最近更新 更多