Изменить цвет определенных слов в текстовом поле

Я создаю построитель запросов 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 в сочетании с Contains в jQuery, но это не дало особого результата.

Keyup: https://api.jquery.com/keyup/

Содержит: https://api.jquery.com/contains-selector/

Я надеюсь, что кто-то может помочь мне с примером или сайтами, на которых я могу найти дополнительную информацию.

С уважением, Йенс


person Community    schedule 10.05.2016    source источник
comment
Вы меняете цвет элемента el.style.color, поэтому он не работает. Вам нужно использовать вещи типа CKEditor. Выполнение этого вручную требует обработки слов в промежутках или div с пользовательскими тегами стиля.   -  person Murtaza Khursheed Hussain    schedule 10.05.2016
comment
Да, я знаю, почему пример не работает. Пример просто для дополнительной информации. Я думал, что, возможно, это будет легко сделать с помощью JQuery, но я думаю, что это действительно слишком сложно.   -  person    schedule 10.05.2016
comment
Рассматривали ли вы использование разных классов стилей, затем выполните поиск / замену для SELECT replace с ‹span class = 'orange'› SELECT ‹/span›.   -  person durbnpoisn    schedule 10.05.2016
comment
Вы каждый раз проверяете все значение текстовой области. Ваш код будет работать, только если содержимое текстового поля будет содержать только одно из этих слов и ничего больше. Вы можете использовать jQuery .split () для захвата каждого слова в массив и сравнения; наверное, лучший способ, просто первое, что пришло в голову.   -  person user2051770    schedule 10.05.2016
comment
Да только мне это показалось не очень полезным ..   -  person    schedule 10.05.2016
comment
@ user2051770 Хороший совет, попробую.   -  person    schedule 10.05.2016


Ответы (6)


Вы не можете изменить цвета слов в <textarea>, но вы можете использовать атрибут contenteditable, чтобы <div>, <span> или <p> выглядели как <textarea>.

Для этого вы можете использовать плагин 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>

person Mohammad    schedule 11.05.2016
comment
Ух ты! На самом деле это отличное решение, его немного сложно с публикацией данных, но я исправлю это с помощью Ajax, и я могу удалить теги html с помощью strip_tag (); Спасибо за ваш ответ! - person ; 11.05.2016
comment
@VenkatSoma Нет, input и textarea не могут иметь дочерний элемент и стиль для содержимого. Целевой элемент должен принимать дочерний элемент. - person Mohammad; 12.09.2018
comment
этот код, кажется, удаляет разрывы строк, есть ли настройка, которая позволила бы ему сохранить разрывы строк. Я использую его для аналогичной настройки, и когда я нажимаю клавишу ввода, он удаляет разрыв строки и помещает все обратно в одну строку. - person Developer Gee; 25.09.2018
comment
@Mohammad, ваше решение отличное! Но, похоже, он не выделяет несколько слов, таких как «не в», как вы упомянули в своих случаях переключения. Есть идеи, почему? - person Souvik Ray; 05.11.2019
comment
@SouvikRay Используйте ключевые слова not и in отдельно в переключателе - person Mohammad; 05.11.2019
comment
@ Мохаммед, ладно, понял! - person Souvik Ray; 07.11.2019
comment
@ Мохаммад, привет! Итак, я работал над вашим кодом, и он отлично работает, за исключением ситуации, когда я пишу предложение и делаю опечатку, когда складываю два слова вместе. Например Hey select mefrom here Как видите, mefrom - это два слова. Теперь я помещаю курсор после e и нажимаю пробел. Но когда я попадаю в пробел, я попадаю в конец предложения. Я попытался настроить ваш код позиционирования курсора, но пока безуспешно. Есть идеи, как я могу это сделать? - person Souvik Ray; 07.11.2019
comment
@SouvikRay Просто удали keydown событие - person Mohammad; 08.11.2019
comment
@ Мохаммад, ты классный! Спасибо, дружище, за уделенное время! - person Souvik Ray; 08.11.2019
comment
Он возвращается к концу кода, когда я пишу qsido в его начале. - person MARSHMALLOW; 20.03.2020
comment
Мне очень нравится этот код, можем ли мы убрать нажатие клавиши пробела, чтобы увидеть реальный эффект? Это означает, что у меня есть тег div, в котором данные автоматически заполняются другой функцией. Хотите использовать свой JS-код для выделения. - person manjesh23; 23.05.2021
comment
@ manjesh23 Удалите обработчик события keyup кода и запустите его после вашей функции. - person Mohammad; 24.05.2021

КОД JS FIDDLE

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);
  });
person prtk712    schedule 14.02.2019
comment
Хорошее решение! Это намного лучше, чем другие. - person ch_g; 31.03.2021

С 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;
        }
<div id="editor" contenteditable="true"></div>

person Hasan A Yousef    schedule 24.09.2020
comment
Мне очень нравится этот код, можем ли мы убрать нажатие клавиши пробела, чтобы увидеть реальный эффект? Это означает, что у меня есть тег div, в котором данные автоматически заполняются другой функцией. Хотите использовать свой JS-код для выделения. - person manjesh23; 23.05.2021

Это не ответ на этот вопрос, но он отвечает на вопрос заголовка, который возникает, когда вы выполняете поиск в Google по выделению слова в текстовой области.

Цветное выделение можно сделать в элементе textarea с помощью встроенной функции API setSelectionRange и селектора css :: selection.

Обратите внимание, что он поддерживает только одно выделение текста за раз и только до тех пор, пока текстовое поле не получит фокус.

  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>

person Community    schedule 07.01.2021

Я ничего не мог поделать с каретом, поэтому я позаимствовал работу других людей, и это сделало код огромным. я не знаю, насколько это быстро, но работает хорошо: T

коды, которые я позаимствовал:

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

Получите смещение начала и конца диапазона относительно его родительского контейнера

you can run with no 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;
}
<div id="editor" spellcheck="false" contenteditable="true"></div>

person Herom123    schedule 07.07.2021
comment
Я имею в виду ... это работает! Хотя я рекомендую отформатировать ваш код, чтобы его было легче читать. Онлайн-инструменты, такие как более симпатичная игровая площадка, помогают. - person Mingye Wang; 08.07.2021
comment
@MingyeWang ой, совсем забыл про форматирование .. спасибо за совет. - person Herom123; 08.07.2021

вы можете использовать этот код

<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>
person Me Sa    schedule 01.10.2020