【问题标题】:Replacing text on-the-fly in contenteditable with pure jQuery用纯 jQuery 即时替换 contenteditable 中的文本
【发布时间】:2015-12-19 21:41:17
【问题描述】:

我在 StackOverflow 上看到了一些关于此的问题,但似乎很难找到基于 jQuery 的解决方案。因此,我想问这个问题。

我想用属性contenteditable="true" 即时替换div 中的文本。

我正在寻找一个基于 jQuery 的解决方案,它将执行以下操作:

  • 即时自动替换书面文本(在您键入时)
  • 能够继续写入(在完成替换的同时)

我查看了 SC 编辑器 (http://www.sceditor.com/),它似乎正是这样做的(例如,如果您尝试输入 :),它会被表情符号替换。

我认为一个好的开始是一个包含所有要替换的元素的数组:

$.settings = {
    path: 'https://example.com/images/',
    emoticons: {
        ':(' : 'stupid.jpg',
        ':)' : 'smart.jpg',
    }
}

我一直找不到这方面的好例子。如果有人可以分享他们的想法和任何代码,我会很高兴。

如何用上面的代码以最好的方式完成替换?

【问题讨论】:

  • 我不知道这是否是最好的方法,但是您可以在输入中添加一个侦听器,并在您输入时让它读取字符,如果最后一个写入的字符与您测试的最后一个情绪相匹配与任何情感相匹配的先前角色。如果我写 :( 当它捕捉到(它会字体为:如果找到替换为你的情感。

标签: javascript jquery contenteditable


【解决方案1】:

我找到了这个。如果您调整它,它可能会满足您的需求。它将 { 替换为 {} 并将 ( 替换为 () 并且光标最终位于中间。

    <script type="text/javascript">
        $(document).ready(function () {
            $("#d").keypress(function (e) {
 
       
                    var charTyped = String.fromCharCode(e.which);
                    if (charTyped == "{" || charTyped == "(") {
                        // Handle this case ourselves
                        e.preventDefault();

                        var sel = window.getSelection();
                        if (sel.rangeCount > 0) {
                            // First, delete the existing selection
                            var range = sel.getRangeAt(0);
                            range.deleteContents();

                            // Insert a text node with the braces/parens
                            var text = (charTyped == "{") ? "{}" : "()";
                            var textNode = document.createTextNode(text);
                            range.insertNode(textNode);

                            // Move the selection to the middle of the text node
                            range.setStart(textNode, 1);
                            range.setEnd(textNode, 1);
                            sel.removeAllRanges();
                            sel.addRange(range);
                        }
                    }
         

            });
        });
    </script>
</head>

<body>
    <div id="d" contentEditable="true">....</div>
</body>
</html>

【讨论】:

    【解决方案2】:
    $('div').keyup(function(){
        //make here for loop which replace all emoticons
        $(this).text().replace(':(', 'stupid.jpg');
    });
    

    【讨论】:

    • 如果您使用的是文本控件,您将无法插入图像。如果您使用的是 div,那么您将必须捕获每个键击检查键并查看应该在其位置使用什么 html 控件,同时跟踪光标应该在哪里。这就是 S C Editor 正在做的事情。
    【解决方案3】:

    在未能找到此问题的答案后发布我最终写的内容。我希望它对来到这个问题寻找答案的其他人有所帮助(:

    我将发布一个更通用的查找和替换解决方案(包含在一个类中)。这适用于内容可编辑的 div,并且在用户键入时工作,此外它不会影响插入符号的位置。此实现使用不区分大小写的搜索(尽管在代码中禁用它很简单)。它的另一个优点是即使您在段落的中间(不仅仅是在行尾)输入它也可以工作,并且可以处理粘贴的文本。试一试!

    class FindAndReplace {
    
    	constructor($contentEditable, findAndReplaceData) {
    
    		var self = this;
    
    		$contentEditable.on('input blur', function () {
    
    			var textNodes = self.getTextNodes($contentEditable);
    
    			textNodes.each(function (i) {
    
    				// Perform all replacements on text
    				findAndReplaceData.forEach(function (findAndReplaceDatum) {
    
    					var find = findAndReplaceDatum.find;
    					var replace = findAndReplaceDatum.replace;
    
    					var regexEscapedFind = self.escapeRegExp(find);
    					var regexEscapedReplace = self.escapeRegExp(replace);
    
    					var regexEscapedCaseInsensitiveFind = self.makeRegexCaseInsensitive(regexEscapedFind);
    
    					// Case insensitive search for the find with a negative lookahead to check its not a case sensitive match of the replacement (aka to check its actually going to make a difference)
    					var regexString = `(?!${regexEscapedReplace})${regexEscapedCaseInsensitiveFind}`;
    
    					do {
    
    						// Get the latest version of the text node
    						textNode = self.getTextNodes($contentEditable)[i];
    						var text = textNode.data;
    
    						var regex = new RegExp(regexString);
    						var matchIndex = text.search(regex);
    						var matchFound = (matchIndex !== -1);
    
    						if (matchFound) {
    
    							// Select the match
    							var range = document.createRange();
    							range.setStart(textNode, matchIndex);
    							range.setEnd(textNode, matchIndex + find.length);
    							// Delete it
    							range.deleteContents();
    
    							// Create the replacement node
    							var textNode = document.createTextNode(replace);
    							// Insert it
    							range.insertNode(textNode);
    
    							// Set the range to the end of the selected node
    							range.collapse(false);
    							// Set the user selection the range
    							var sel = window.getSelection();
    							sel.removeAllRanges();
    							sel.addRange(range);
    
    							// Make sure there a no adjacent or empty text nodes
    							$contentEditable[0].normalize();
    
    						}
    
    					} while (matchFound)
    
    				});
    
    			});
    
    		});
    
    	}
    
    	escapeRegExp(string) {
    
    		// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
    		return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
    
    	}
    
    	getTextNodes($contentEditable) {
    		return $contentEditable.contents().filter(function () {
    			return this.nodeType == 3; // Text node
    		});
    
    	}
    
    	makeRegexCaseInsensitive(string) {
    
    		var stringArray = string.split('');
    
    		stringArray = stringArray.map(function (char) {
    
    			if (char.toLowerCase() !== char.toUpperCase())
    				return '[' + char.toLowerCase() + char.toUpperCase() + ']';
    			else
    				return char;
    
    		});
    
    		return stringArray.join('');
    
    	}
    
    }
    div {
      border: 1px solid black;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <script>
    
    $(function(){
    
      var findAndReplaceData = [
    	  {
          'find': 'find me',
          'replace': 'and replace with me!'
        },
        {
          'find': 'foo',
          'replace': 'bar'
        },
        {
          'find': 'no',
          'replace': 'yes'
        }
      ];
    
      $contentEditable = $('div');
    
      new FindAndReplace($contentEditable,findAndReplaceData);
    
    });
    
    </script>
    
    <div contenteditable="true"></div>

    【讨论】:

      猜你喜欢
      • 2011-11-16
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 2012-07-04
      • 2011-04-29
      • 2012-09-24
      • 2012-06-13
      • 1970-01-01
      相关资源
      最近更新 更多