在contenteditable div中替换字符串

时间:2018-04-28 20:14:20

标签: javascript jquery html

我试图替换一个可信的div中的某个字符串。 Replace()函数对我不起作用,不确定我哪里出错。

我的代码:

<div contenteditable="true" id="contenteditableDiv"></div>

$(document).ready(function(){
    $('#contenteditableDiv').on('keyup', function() {

        var content = $('#contenteditableDiv').html();
        var watcher = (content.match(/cat/gi)||[]).length;

        if (watcher === 1) {
            $('#contenteditableDiv').html().replace(/cat/g, "dog");
        };
    });
});

这是一个有点简化的例子(用“&#39; dog&#39;”代替“&#39; cat&#39;”这个词。最后,我计划在键入一系列字符串时触发此操作(即四个连续的换行符)。

5 个答案:

答案 0 :(得分:2)

问题

从我从问题中收集到的是:

  • 正在使用contenteditable <div>

  • 当用户输入时,如果输入关键字(“cat”),它将被新关键字(“dog”)替换。

  • keyup事件无法促成此行为。

Explination

keyup之类的键盘事件过于气馁:

  

“可聚焦元素可能因浏览器而异,但表单元素始终可以获得焦点,因此这种事件类型是合理的候选者。”

- jQuery - .keyup()

因此,接收键盘事件等事件的关键是能够获得focus。可以100%获得focus时间的元素是表单元素(例如<input><textarea>等)。虽然键盘事件在表单元素上是可以的,但changeinput事件专门用于表单事件。

解决方案

由于OP代码需要contenteditable <div>而不是<textarea>,因此Demo有:

  • div#view

  • 一个contenteditable
  • textarea#edit下的一个div#view,只有光标可见。

  • 当用户输入div#view时,textarea#edit实际上正在侦听input事件,div#view正在侦听keyup事件。< / p>

  • input事件发生时,#edit会立即将#view的文本设置为其自身值的文本。在每个keyup事件#view上将focus设置回#edit

  • 基本上,div#viewtextarea#edit占据相同的空间,#view位于前方#edit位于#view之后。用户输入是#edit上的透明文字,但其光标是可见的(因为在focus事件期间它始终从#view获得keyup#view#edit获取其文字。

作为奖励,用户输入要更改的任何字符串(如“cat”)并输入要更改的字符串(如“dog”)。

注意:我之所以选择这样一个错综复杂的解决方案,是因为游标的focus。在没有人的情况下打字会感觉很人为,并且使用弹出回到开头的光标进行打字会令人迷惑。

演示

在演示中评论的详细信息

如果要呈现HTML,请参阅jQuery部分中的注释

$(document).ready(function() {

  // textarea listens for input event...
  $('#edit').on('input', function() {

    // Collect values from inputs and textarea 
    var from = $('#from').val();
    var to = $('#to').val();
    var value = $(this).val();

    /* if the value of input#from is in the value of textarea...
    || indexOf() will return its index number...
    || so if indexOf() doesn't find it then it returns -1
    */
    if (value.indexOf(from) !== -1) {
    
      // Using RegExp Object for variable string
      var rgx = new RegExp(from, 'g');
      
      // New value of textarea#edit replaced 'from' with 'to'
      value = value.replace(rgx, to);
    }
    
    // The text of div#view is the new value of #edit
    /* Change .text to .html is you want to render HTML but it
    || be disorienting as what is actually typed is not seen.
    || A more feasible solution is to move #edit below view and
    || change #edit color to a visible color.
    */
    $('#view').text(value);
    
    // The value of #edit is the new value
    $(this).val(value);
  });

  // #view listens for keydown event...
  $('#view').on('keydown', function() {

    // Move focus to #edit
    $('#edit')[0].focus();
  });
});
html,
body {
  font: 400 16px/1.3 Consolas;
}


/* Wrap fieldset.main around both textarea and div 
|| div will be on top of textarea because they are absolute
*/

.main {
  position: relative;
  width: 90vw;
  border: 0
}

input {
  font: inherit;
  width: 20ch;
}


/* Only textarea#edit's cursor is visible */

#edit {
  border: 0;
  outline: 0;
  color: transparent;
  caret-color: red;
  position: absolute;
  width: 100%;
  font: inherit;
  left: 2px;
}


/* Editable div#view is over textarea#edit */


/* textarea#edit will actually get an input event */


/* User will see the div's text that comes from #edit*/


/* The value typed into #edit is transparent so user only sees
div#view's text and textarea#edit's cursor */

#view {
  position: absolute;
  pointer-events: none;
  z-index: 1;
  outline: 3px inset grey;
  width: 100%;
  min-height: 50px;
  left: 2px;
}
<!--UI enter target string and new string-->
<fieldset class='ui'>
  <legend>Convert String</legend>
  <label>From: </label><input id='from'>
  <label>To: </label><input id='to'>
</fieldset>

<!--Wrap editable div and textarea in an relative element-->
<fieldset class='main'>

  <!--Div and textaera are absolute see CSS-->
  <div id="view" contenteditable="true"></div>
  <textarea id='edit'></textarea>
</fieldset>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

答案 1 :(得分:1)

您替换了字符串但未分配回来。

请注意,更换后,cousor不会停留在您输入的位置。

&#13;
&#13;
$(document).ready(function() {
  $('#contenteditableDiv').on('keyup', function(e) {
    var $this = $(this)
    var content = $this.html();
    var watcher = (content.match(/cat/gi) || []).length;
    
    var position = e

    if (watcher === 1) {
      var text = content.replace(/cat/g, "dog");
      $this.html(text);
    };
  });
});
&#13;
div {
  border: 1px gray solid;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" id="contenteditableDiv"></div>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

这个更简单的解决方案呢?

&#13;
&#13;
$("#contenteditableDiv").on('keyup', function() {
  $(this).val($(this).val().replace(/cat/g, "dog"));
});
&#13;
#contenteditableDiv {
  width: 90%;
  height: 100px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="contenteditableDiv"></textarea>
&#13;
&#13;
&#13;

你的问题是$('#contenteditableDiv').html()在呈现时返回元素的值,即为空 要获取当前值,您需要使用.val()

检查此问题,了解何时使用.html().val().text()
When do I use .val() vs .innerHTML?

答案 3 :(得分:0)

如果元素设置为contenteditable,则没有任何缺点。

它与任何其他元素一样,以下代码段使用jquery NOT ,这是纯ecma6 javascript replace()

自2015年以来在浏览器中推出。您的图书馆很难有机会处理好现代js,可能存在冲突。

&#13;
&#13;
onload =(()=>{
  ctd.innerHTML = ctd.innerHTML.replace("world","<mark>world</mark>")
})
&#13;
<div contenteditable="true" id="ctd">Hello world</div>
&#13;
&#13;
&#13;

这就是说,关于具体的contenteditable属性,我们可以使用 - ,因为不是很长时间 - document.execCommand(),它与浏览器{{3}一起使用}}

查看editing api上的更多功能。 最后的话,我的观点,jquery已经现在

Ecma6是要走的路,我们可以用更少的代码,更快的速度和非常接近完整的浏览器支持来完成jquery提供的所有功能。

Js就是他现在因为jquery。

答案 4 :(得分:0)

在找到这个帖子并自己在这个主题上挣扎了一段时间后,我创建了一个 npm 包,它可以自动转换 contenteditable 元素中的给定关键字。

https://www.npmjs.com/package/replace-keywords