添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

这周碰到一个东西, contentEditable ,它是用来指定一个元素是否是可编辑的,这也是富文本编辑器实现的底层支持,网上关于这部分东西的资料比较少或者不全,所以我来整理下关于这个属性,和可编辑区域的一些操作吧, 比如获取光标位置,设置光标,往可编辑区域光标处插入内容等等

HTML中的contentEditable的属性可以打开某些元素的可编辑状态.也许你没用过contentEditable属性.甚至从未听说过.contentEditable的作用相当神奇.可以让div或整个网页,以及span等等元素设置为可写。我们最常用的输入文本内容便是input与textarea,使用contentEditable属性后,可以在div,table,p,span,body,等等很多元素中输入内容.

设置一个容器为可编辑区域: 设置contentEditable属性

<p contentEditable style="border: 1px solid red;">grsd</p> <div contentEditable style="border: 1px solid red;">rsdgsdg </div> </body>

设置placeholder:
这个不像表单一样,给属性加上placeholder属性指定值就可以了,还需要配合特殊的样式 :empty 做设置

	<style type="text/css">
			.content:empty::before {
				content: attr(placeholder);
				font-size: 14px;
				color: #CCC;
				line-height: 21px;
				padding-top: 20px;
			.content {
				border: 1px solid black;
		</style>
		<div contentEditable class="content" placeholder="请输入不少于150字"></div>
	</body>

回车时,在标记生成上的不同点

因为各个浏览器在标记生成上的不同,因此跨浏览器使用 contenteditable 一直以来都是痛点,例如一些看起来十分简单的事情,如: 当你按下Enter/Return键在可编辑区域中创建一个新的文本行时,不同主流浏览器对此有不同处理(Firefox 插入<br>、IE/Opera将使用<p>、 Chrome/Safari 将使用 <div>)幸运的是在现代浏览器中,这些不同都趋于一致了。截止到Firefox 60,火狐开始使用<div>元素来包裹新生成的文本行,以与Chrome, modern Opera, Edge, and Safari.的行为趋于一致
在这里插入图片描述

改变回车时插入的标签:
如果你想使用不同的方式创建新的段落,上面所有浏览器都支持document.execCommand方法,该方法提供的 defaultParagraphSeparator 命令能够让你以不同的方式创建新的段落例如, 使用 <p> 元素:

document.execCommand("defaultParagraphSeparator", false, "p");

现在在编辑器中按回车就变成p标签了
在这里插入图片描述

document.execCommand的强大:

上面只是document.execCommand的一个命令演示

当一个HTML文档切换到设计模式时,document暴露 execCommand 方法,该方法允许运行命令来操纵可编辑内容区域的元素。
大多数命令影响document的 selection(粗体,斜体等),当其他命令插入新元素(添加链接)或影响整行(缩进)。当使用contentEditable时,调用 execCommand() 将影响当前活动的可编辑元素

命令很多,这里就不列举出来,具体可以参考官方文档document.execCommand命令大全

基于document.execCommand的这些命令我们可以做一个小型的富文本编辑器:

<!doctype html>
		<title>Rich Text Editor</title>
		<script type="text/javascript">
			var oDoc, sDefTxt;
			function initDoc() {
				oDoc = document.getElementById("textBox");
				sDefTxt = oDoc.innerHTML;
				if(document.compForm.switchMode.checked) {
					setDocMode(true);
			function formatDoc(sCmd, sValue) {
				if(validateMode()) {
					document.execCommand(sCmd, false, sValue);
					oDoc.focus();
			function validateMode() {
				if(!document.compForm.switchMode.checked) {
					return true;
				alert("Uncheck \"Show HTML\".");
				oDoc.focus();
				return false;
			function setDocMode(bToSource) {
				var oContent;
				if(bToSource) {
					oContent = document.createTextNode(oDoc.innerHTML);
					oDoc.innerHTML = "";
					var oPre = document.createElement("pre");
					oDoc.contentEditable = false;
					oPre.id = "sourceText";
					oPre.contentEditable = true;
					oPre.appendChild(oContent);
					oDoc.appendChild(oPre);
					document.execCommand("defaultParagraphSeparator", false, "div");
				} else {
					if(document.all) {
						oDoc.innerHTML = oDoc.innerText;
					} else {
						oContent = document.createRange();
						oContent.selectNodeContents(oDoc.firstChild);
						oDoc.innerHTML = oContent.toString();
					oDoc.contentEditable = true;
				oDoc.focus();
			function printDoc() {
				if(!validateMode()) {
					return;
				var oPrntWin = window.open("", "_blank", "width=450,height=470,left=400,top=100,menubar=yes,toolbar=no,location=no,scrollbars=yes");
				oPrntWin.document.open();
				oPrntWin.document.write("<!doctype html><html><head><title>Print<\/title><\/head><body οnlοad=\"print();\">" + oDoc.innerHTML + "<\/body><\/html>");
				oPrntWin.document.close();
		</script>
		<style type="text/css">
			.intLink {
				cursor: pointer;
			img.intLink {
				border: 0;
			#toolBar1 select {
				font-size: 10px;
			#textBox {
				width: 540px;
				height: 200px;
				border: 1px #000000 solid;
				padding: 12px;
				overflow: scroll;
			#textBox #sourceText {
				padding: 0;
				margin: 0;
				min-width: 498px;
				min-height: 200px;
			#editMode label {
				cursor: pointer;
		</style>
	</head>
	<body onload="initDoc();">
		<form name="compForm" method="post" action="sample.php" onsubmit="if(validateMode()){this.myDoc.value=oDoc.innerHTML;return true;}return false;">
			<input type="hidden" name="myDoc">
			<div id="toolBar1">
				<select onchange="formatDoc('formatblock',this[this.selectedIndex].value);this.selectedIndex=0;">
					<option selected>- formatting -</option>
					<option value="h1">Title 1 &lt;h1&gt;</option>
					<option value="h2">Title 2 &lt;h2&gt;</option>
					<option value="h3">Title 3 &lt;h3&gt;</option>
					<option value="h4">Title 4 &lt;h4&gt;</option>
					<option value="h5">Title 5 &lt;h5&gt;</option>
					<option value="h6">Subtitle &lt;h6&gt;</option>
					<option value="p">Paragraph &lt;p&gt;</option>
					<option value="pre">Preformatted &lt;pre&gt;</option>
				</select>
				<select onchange="formatDoc('fontname',this[this.selectedIndex].value);this.selectedIndex=0;">
					<option class="heading" selected>- font -</option>
					<option>Arial</option>
					<option>Arial Black</option>
					<option>Courier New</option>
					<option>Times New Roman</option>
				</select>
				<select onchange="formatDoc('fontsize',this[this.selectedIndex].value);this.selectedIndex=0;">
					<option class="heading" selected>- size -</option>
					<option value="1">Very small</option>
					<option value="2">A bit small</option>
					<option value="3">Normal</option>
					<option value="4">Medium-large</option>
					<option value="5">Big</option>
					<option value="6">Very big</option>
					<option value="7">Maximum</option>
				</select>
				<select onchange="formatDoc('forecolor',this[this.selectedIndex].value);this.selectedIndex=0;">
					<option class="heading" selected>- color -</option>
					<option value="red">Red</option>
					<option value="blue">Blue</option>
					<option value="green">Green</option>
					<option value="black">Black</option>
				</select>
				<select onchange="formatDoc('backcolor',this[this.selectedIndex].value);this.selectedIndex=0;">
					<option class="heading" selected>- background -</option>
					<option value="red">Red</option>
					<option value="green">Green</option>
					<option value="black">Black</option>
				</select>
			</div>
			<div id="toolBar2">
				<img class="intLink" title="Clean" onclick="if(validateMode()&&confirm('Are you sure?')){oDoc.innerHTML=sDefTxt};" src="data:image/gif;base64,R0lGODlhFgAWAIQbAD04KTRLYzFRjlldZl9vj1dusY14WYODhpWIbbSVFY6O7IOXw5qbms+wUbCztca0ccS4kdDQjdTLtMrL1O3YitHa7OPcsd/f4PfvrvDv8Pv5xv///yH5BAEKAB8ALAAAAAAWABYAAAV84CeOZGmeaKqubMteyzK547QoBcFWTm/jgsHq4rhMLoxFIehQQSAWR+Z4IAyaJ0kEgtFoLIzLwRE4oCQWrxoTOTAIhMCZ0tVgMBQKZHAYyFEWEV14eQ8IflhnEHmFDQkAiSkQCI2PDC4QBg+OAJc0ewadNCOgo6anqKkoIQA7" />
				<img class="intLink" title="Print" onclick="printDoc();" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oEBxcZFmGboiwAAAAIdEVYdENvbW1lbnQA9syWvwAAAuFJREFUOMvtlUtsjFEUx//n3nn0YdpBh1abRpt4LFqtqkc3jRKkNEIsiIRIBBEhJJpKlIVo4m1RRMKKjQiRMJRUqUdKPT71qpIpiRKPaqdF55tv5vvusZjQTjOlseUkd3Xu/3dPzusC/22wtu2wRn+jG5So/OCDh8ycMJDflehMlkJkVK7KUYN+ufzA/RttH76zaVocDptRxzQtNi3mRWuPc+6cKtlXZ/sddP2uu9uXlmYXZ6Qm8v4Tz8lhF1H+zDQXt7S8oLMXtbF4e8QaFHjj3kbP2MzkktHpiTjp9VH6iHiA+whtAsX5brpwueMGdONdf/2A4M7ukDs1JW662+XkqTkeUoqjKtOjm2h53YFL15pSJ04Zc94wdtibr26fXlC2mzRvBccEbz2kiRFD414tKMlEZbVGT33+qCoHgha81SWYsew0r1uzfNylmtpx80pngQQ91LwVk2JGvGnfvZG6YcYRAT16GFtW5kKKfo1EQLtfh5Q2etT0BIWF+aitq4fDbk+ImYo1OxvGF03waFJQvBCkvDffRyEtxQiFFYgAZTHS0zwAGD7fG5TNnYNTp8/FzvGwJOfmgG7GOx0SAKKgQgDMgKBI0NJGMEImpGDk5+WACEwEd0ywblhGUZ4Hw5OdUekRBLT7DTgdEgxACsIznx8zpmWh7k4rkpJcuHDxCul6MDsmmBXDlWCH2+XozSgBnzsNCEE4euYV4pwCpsWYPW0UHDYBKSWu1NYjENDReqtKjwn2+zvtTc1vMSTB/mvev/WEYSlASsLimcOhOBJxw+N3aP/SjefNL5GePZmpu4kG7OPr1+tOfPyUu3BecWYKcwQcDFmwFKAUo90fhKDInBCAmvqnyMgqUEagQwCoHBDc1rjv9pIlD8IbVkz6qYViIBQGTJPx4k0XpIgEZoRN1Da0cij4VfR0ta3WvBXH/rjdCufv6R2zPgPH/e4pxSBCpeatqPrjNiso203/5s/zA171Mv8+w1LOAAAAAElFTkSuQmCC">
				<img class="intLink" title="Undo" onclick="formatDoc('undo');" src="data:image/gif;base64,R0lGODlhFgAWAOMKADljwliE33mOrpGjuYKl8aezxqPD+7/I19DV3NHa7P///yH5BAEKAA8ALAAAAAAWABYAAARR8MlJq7046807TkaYeJJBnES4EeUJvIGapWYAC0CsocQ7SDlWJkAkCA6ToMYWIARGQF3mRQVIEjkkSVLIbSfEwhdRIH4fh/DZMICe3/C4nBQBADs=" />
				<img class="intLink" title="Redo" onclick="formatDoc('redo');" src="data:image/gif;base64,R0lGODlhFgAWAMIHAB1ChDljwl9vj1iE34Kl8aPD+7/I1yH5BAEKAAcALAAAAAAWABYAAANKeLrc/jDKSesyphi7SiEgsVXZEATDICqBVJjpqWZt9NaEDNbQK1wCQsxlYnxMAImhyDoFAElJasRRvAZVRqqQXUy7Cgx4TC6bswkAOw==" />
				<img class="intLink" title="Remove formatting" onclick="formatDoc('removeFormat')" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9oECQMCKPI8CIIAAAAIdEVYdENvbW1lbnQA9syWvwAAAuhJREFUOMtjYBgFxAB501ZWBvVaL2nHnlmk6mXCJbF69zU+Hz/9fB5O1lx+bg45qhl8/fYr5it3XrP/YWTUvvvk3VeqGXz70TvbJy8+Wv39+2/Hz19/mGwjZzuTYjALuoBv9jImaXHeyD3H7kU8fPj2ICML8z92dlbtMzdeiG3fco7J08foH1kurkm3E9iw54YvKwuTuom+LPt/BgbWf3//sf37/1/c02cCG1lB8f//f95DZx74MTMzshhoSm6szrQ/a6Ir/Z2RkfEjBxuLYFpDiDi6Af///2ckaHBp7+7wmavP5n76+P2ClrLIYl8H9W36auJCbCxM4szMTJac7KzaR3H1w2cfWAgafPbqs5g7D95++/P1B4+ECK8tAwMDw/1H7159+/7r7ZcvPz4fOHbzEwMDwx8GBgaGnNatfHZx8zqrJ+4VJBh5CQEGOySEua/v3n7hXmqI8WUGBgYGL3vVG7fuPK3i5GD9/fja7ZsMDAzMG/Ze52mZeSj4yu1XEq/ff7W5dvfVAS1lsXc4Db7z8C3r8p7Qjf///2dnZGxlqJuyr3rPqQd/Hhyu7oSpYWScylDQsd3kzvnH738wMDzj5GBN1VIWW4c3KDon7VOvm7S3paB9u5qsU5/x5KUnlY+eexQbkLNsErK61+++VnAJcfkyMTIwffj0QwZbJDKjcETs1Y8evyd48toz8y/ffzv//vPP4veffxpX77z6l5JewHPu8MqTDAwMDLzyrjb/mZm0JcT5Lj+89+Ybm6zz95oMh7s4XbygN3Sluq4Mj5K8iKMgP4f0fv77//8nLy+7MCcXmyYDAwODS9jM9tcvPypd35pne3ljdjvj26+H2dhYpuENikgfvQeXNmSl3tqepxXsqhXPyc666s+fv1fMdKR3TK72zpix8nTc7bdfhfkEeVbC9KhbK/9iYWHiErbu6MWbY/7//8/4//9/pgOnH6jGVazvFDRtq2VgiBIZrUTIBgCk+ivHvuEKwAAAAABJRU5ErkJggg==">
				<img class="intLink" title="Bold" onclick="formatDoc('bold');" src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWABYAQAInhI+pa+H9mJy0LhdgtrxzDG5WGFVk6aXqyk6Y9kXvKKNuLbb6zgMFADs=" />
				<img class="intLink" title="Italic" onclick="formatDoc('italic');" src="data:image/gif;base64,R0lGODlhFgAWAKEDAAAAAF9vj5WIbf///yH5BAEAAAMALAAAAAAWABYAAAIjnI+py+0Po5x0gXvruEKHrF2BB1YiCWgbMFIYpsbyTNd2UwAAOw==" />
				<img class="intLink" title="Underline" onclick="formatDoc('underline');" src="data:image/gif;base64,R0lGODlhFgAWAKECAAAAAF9vjyH5BAEAAAIALAAAAAAWABYAAAIrlI+py+0Po5zUgAsEzvEeL4Ea15EiJJ5PSqJmuwKBEKgxVuXWtun+DwxCCgA7" />
				<img class="intLink" title="Left align" onclick="formatDoc('justifyleft');" src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWABYAQAIghI+py+0Po5y02ouz3jL4D4JMGELkGYxo+qzl4nKyXAAAOw==" />
				<img class="intLink" title="Center align" onclick="formatDoc('justifycenter');" src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWABYAQAIfhI+py+0Po5y02ouz3jL4D4JOGI7kaZ5Bqn4sycVbAQA7" />
				<img class="intLink" title="Right align" onclick="formatDoc('justifyright');" src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWABYAQAIghI+py+0Po5y02ouz3jL4D4JQGDLkGYxouqzl43JyVgAAOw==" />
				<img class="intLink" title="Numbered list" onclick="formatDoc('insertorderedlist');" src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAADljwliE35GjuaezxtHa7P///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKSespwjoRFvggCBUBoTFBeq6QIAysQnRHaEOzyaZ07Lu9lUBnC0UGQU1K52s6n5oEADs=" />
				<img class="intLink" title="Dotted list" onclick="formatDoc('insertunorderedlist');" src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAAB1ChF9vj1iE33mOrqezxv///yH5BAEAAAcALAAAAAAWABYAAAMyeLrc/jDKSesppNhGRlBAKIZRERBbqm6YtnbfMY7lud64UwiuKnigGQliQuWOyKQykgAAOw==" />
				<img class="intLink" title="Quote" onclick="formatDoc('formatblock','blockquote');" src="data:image/gif;base64,R0lGODlhFgAWAIQXAC1NqjFRjkBgmT9nqUJnsk9xrFJ7u2R9qmKBt1iGzHmOrm6Sz4OXw3Odz4Cl2ZSnw6KxyqO306K63bG70bTB0rDI3bvI4P///yH5BAEKAB8ALAAAAAAWABYAAAVP4CeOZGmeaKqubEs2CekkErvEI1zZuOgYFlakECEZFi0GgTGKEBATFmJAVXweVOoKEQgABB9IQDCmrLpjETrQQlhHjINrTq/b7/i8fp8PAQA7" />
				<img class="intLink" title="Delete indentation" onclick="formatDoc('outdent');" src="data:image/gif;base64,R0lGODlhFgAWAMIHAAAAADljwliE35GjuaezxtDV3NHa7P///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKCQG9F2i7u8agQgyK1z2EIBil+TWqEMxhMczsYVJ3e4ahk+sFnAgtxSQDqWw6n5cEADs=" />
				<img class="intLink" title="Add indentation" onclick="formatDoc('indent');" src="data:image/gif;base64,R0lGODlhFgAWAOMIAAAAADljwl9vj1iE35GjuaezxtDV3NHa7P///yH5BAEAAAgALAAAAAAWABYAAAQ7EMlJq704650B/x8gemMpgugwHJNZXodKsO5oqUOgo5KhBwWESyMQsCRDHu9VOyk5TM9zSpFSr9gsJwIAOw==" />
				<img class="intLink" title="Hyperlink" onclick="var sLnk=prompt('Write the URL here','http:\/\/');if(sLnk&&sLnk!=''&&sLnk!='http://'){formatDoc('createlink',sLnk)}" src="data:image/gif;base64,R0lGODlhFgAWAOMKAB1ChDRLY19vj3mOrpGjuaezxrCztb/I19Ha7Pv8/f///yH5BAEKAA8ALAAAAAAWABYAAARY8MlJq7046827/2BYIQVhHg9pEgVGIklyDEUBy/RlE4FQF4dCj2AQXAiJQDCWQCAEBwIioEMQBgSAFhDAGghGi9XgHAhMNoSZgJkJei33UESv2+/4vD4TAQA7" />
				<img class="intLink" title="Cut" onclick="formatDoc('cut');" src="data:image/gif;base64,R0lGODlhFgAWAIQSAB1ChBFNsRJTySJYwjljwkxwl19vj1dusYODhl6MnHmOrpqbmpGjuaezxrCztcDCxL/I18rL1P///yH5BAEAAB8ALAAAAAAWABYAAAVu4CeOZGmeaKqubDs6TNnEbGNApNG0kbGMi5trwcA9GArXh+FAfBAw5UexUDAQESkRsfhJPwaH4YsEGAAJGisRGAQY7UCC9ZAXBB+74LGCRxIEHwAHdWooDgGJcwpxDisQBQRjIgkDCVlfmZqbmiEAOw==" />
				<img class="intLink" title="Copy" onclick="formatDoc('copy');" src="data:image/gif;base64,R0lGODlhFgAWAIQcAB1ChBFNsTRLYyJYwjljwl9vj1iE31iGzF6MnHWX9HOdz5GjuYCl2YKl8ZOt4qezxqK63aK/9KPD+7DI3b/I17LM/MrL1MLY9NHa7OPs++bx/Pv8/f///yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAAGrpy+wsbKzIiEAOw==" />
				<img class="intLink" title="Paste" onclick="formatDoc('paste');" src="data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrpqbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f///yH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvBSyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQo9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAAMOaK+bLAOrtLUyt7i5uiUhADs=" />
			</div>
			<div id="textBox" contenteditable="true">
				<p>Lorem ipsum</p>
			</div>
			<p id="editMode"><input type="checkbox" name="switchMode" id="switchBox" onchange="setDocMode(this.checked);" /> <label for="switchBox">Show HTML</label></p>
			<p><input type="submit" value="Send" /></p>
		</form>
	</body>
</html>

在这里插入图片描述
是不是很酷?

window.getSelection():文档地址

Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。要获取用于检查或修改的 Selection 对象,请调用 window.getSelection()

Selection 对象所对应的是用户所选择的 ranges (区域),俗称拖蓝。默认情况下,该函数只针对一个区域,我们可以这样使用这个函数:

var selObj = window.getSelection();
var range  = selObj.getRangeAt(0);

例子: 我写了如下代码来一起探究下这两个是什么东西吧
每次我拖动完,或者点击完鼠标的时候,都会打印selObj,查看selObj对象,看看里面有什么属性

<div>我是p标签的内容</div> <p>我是p标签的内容</p> <li>li1</li> <li>li2</li> </body> <script type="text/javascript"> document.onmouseup=function(){ var selObj = window.getSelection(); console.log(selObj) var range = selObj.getRangeAt(0); console.log(range) </script>

在这里插入图片描述
可以看到window.getSelection()打印的对象就是我们选中区域的对象,对象里面的属性值,我来介绍以下吧
在这里插入图片描述
range对象里面的信息就简洁很多,这个我就不介绍了,和selection对象是一样的
在这里插入图片描述

当然range对象selection对象原型上也有很多的方法提供给我们使用,可以自行查阅文档
selection对象的方法
range对象的方法

我们要说的是基于这些方法,我们如何做到在可编辑的div或容器中往光标处插入内容,返回光标位置

通过js的方式在可编辑区域的光标处插入文本:

方法一:较完整的,考虑兼容,插入后,光标自动设置到插入后的位置

<!DOCTYPE html>
<html lang="zh">
	<meta charset="UTF-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<meta http-equiv="X-UA-Compatible" content="ie=edge" />
	<title>Document</title>
</head>
	<div class="box" contenteditable  style="border: 1px solid red;">
		我是可编辑的div
	</div>
	<button onclick="pasteHtmlAtCaret('我是插入的内容')">插入</button>
</body>
<script type="text/javascript">
	function pasteHtmlAtCaret(html) {
    var sel, range;
    if (window.getSelection) {
        // IE9 and non-IE
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();
            // Range.createContextualFragment() would be useful here but is
            // only relatively recently standardized and is not supported in
            // some browsers (IE9, for one)
            var el = document.createElement("div");
            el.innerHTML = html;
            var frag = document.createDocumentFragment(), node, lastNode;
            while ( (node = el.firstChild) ) {
                lastNode = frag.appendChild(node);
            range.insertNode(frag);
            // Preserve the selection
            if (lastNode) {
                range = range.cloneRange();
                range.setStartAfter(lastNode);
                range.collapse(true);
                sel.removeAllRanges();
                sel.addRange(range);
    } else if (document.selection && document.selection.type != "Control") {
        // IE < 9
        document.selection.createRange().pasteHTML(html);
</script>
</html>

方法二:可插入一段html字符串,可被解析

<div id="box" contentEditable>我是p标签的内容</div> </body> <script type="text/javascript"> document.getElementById("box").onmouseup = function() { insertHtmlAtCursor("<strong>666</strong>") //插入一个HTML字符串: function insertHtmlAtCursor(html) { var range, node; range = window.getSelection().getRangeAt(0); node = range.createContextualFragment(html); range.insertNode(node); </script>

方法三: 插入一段文本

<div id="box" contentEditable>我是p标签的内容</div> </body> <script type="text/javascript"> document.getElementById("box").onmouseup = function() { insertTextAtCursor("<strong>666</strong>") function insertTextAtCursor(txt) { var sel = window.getSelection(); var iEnd = sel.anchorOffset; var htmldata = sel.anchorNode.data; if(htmldata) { var finaldata = htmldata.substring(0, iEnd) + txt + htmldata.substring(iEnd); sel.anchorNode.textContent = finaldata } else { sel.anchorNode.textContent = txt </script>

方法四: 插入一个节点

<div id="box" contentEditable>我是p标签的内容</div> </body> <script type="text/javascript"> document.getElementById("box").onmouseup = function() { insertTextAtCursor("<strong>666</strong>") function insertTextAtCursor(text) { var sel = window.getSelection(); if(sel.getRangeAt && sel.rangeCount) { var range = sel.getRangeAt(0); range.deleteContents(); range.insertNode(document.createTextNode(text)); </script>

总结了以上方式,大概能满足你插入的基本需求了

获取光标位置:

 console.log(window.getSelection().anchorOffset)  //起始点位置
 console.log(window.getSelection().focusOffset)   //末尾点位置

获取选中区域的文本:

document.onmouseup=function(){
			 console.log(window.getSelection().toString())

光标移动到最后:

<div id="box" contentEditable>我是p标签的内容</div> </body> <script type="text/javascript"> document.getElementById("box").onmouseup = function() { set_focus(this) //光标移动到最后 function set_focus(el) { // el.focus(); //创建一个range范围对象 var range = document.createRange(); //用于设置 Range,使其包含一个 Node的内容。 range.selectNodeContents(el); //将包含着的这段内容的光标设置到最后去,true 折叠到 Range 的 start 节点,false 折叠到 end 节点。如果省略,则默认为 false . range.collapse(false); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); </script>

记录光标和恢复光标:通过一个例子演示

<div id="box" contentEditable>我是p标签的内容</div> <button id="saveBtn">记录光标位置</button> <button id="restoreBtn">恢复光标位置</button> </body> <script type="text/javascript"> //全局变量用来存放range变量,恢复的时候使用 let range = null document.getElementById("saveBtn").onclick=function(){ range = saveSelection() document.getElementById("restoreBtn").onclick=function(){ restoreSelection(range) function saveSelection() { if(window.getSelection) { sel = window.getSelection(); if(sel.getRangeAt && sel.rangeCount) { return sel.getRangeAt(0); } else if(document.selection && document.selection.createRange) { return document.selection.createRange(); return null; function restoreSelection(range) { if(range) { if(window.getSelection) { sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } else if(document.selection && range.select) { range.select(); </script>

先这么多,有新的需求或者想起来再补

这周碰到一个骚东西,contentEditable ,它是用来指定一个元素是否是可编辑的,这也是富文本编辑器实现的底层支持,网上关于这部分东西的资料比较少或者不全,所以我来整理下关于这个属性,和可编辑区域的一些操作吧,比如获取光标位置,设置光标,往可编辑区域光标处插入内容等等HTML中的contentEditable的属性可以打开某些元素的可编辑状态.也许你没用过contentEditable属性.甚至从未听说过.contentEditable的作用相当神奇.可以让div或整个网页,以及span等等元素 对于最新版本: < script src =" //cdn.jsdelivr.net/npm/medium-editor@latest/dist/js/medium-editor.min.js " > </ script > < link rel =" stylesheet " href =" //cdn.jsdelivr.net/npm/medium-editor@latest/dist/css/medium-editor.min.css " type =" text/css " media =" screen "
vue-input-contenteditable 输入不受input[type='text']限制的精美输入。 Vue组件包装器,可通过您期望的所有功能进行contenteditable : npm i vue-input-contenteditable 下面是单个文件组件中使用的组件示例。 导入后,请确保将其添加到您的components属性中,然后它将在您的模板中可用。 <template> <input-contenteditable v-model="myModel" _is="p" :placeholder="myPlaceHolder" :maxlength="25" /> </template> [removed] import InputContentedit
var _div = document.querySelector('.discuss_area'); var range = document.createRange(); range.selectNodeContents(_div); range.collapse(
文章目录简易 div 输入框1.获取光标位置2.设置光标位置3.设置选中区域4.获取选中内容5.在光标插入内容 简易 div 输入框 HTML5规范引入了 contenteditable 属性,它几乎可以用在任何元素上,只要添加这一属性 即可变为可编译区域。查看详情 一个简单的 <div> 输入框: <style> .editdiv{ min-heigh...
文章目录selection对象术语属性方法 window.getSelection(),返回一个Selection对象,表示用户选择的文本范围或光标的当前位置selection对象 先来看下面两个selection结果: selection对象一: selection对象二: 很奇怪,为什么同样选中一段文字,为什么selection对象的属性会不一样呢? 那就需要明确一下Selection...
开发中,时常会遇到一个开发场景。当我们在编辑一个富文本的时候。当用户选择了某些文字。我们需要弹出一个窗,让用户选择是否把它变成可粗体,比如下面这个图 当然,今天不会直接敲出这个效果,而是解析下而已。毕竟敲出来对新手不友好,需要给予更多的时间思考 通过测试多次。我们发现了几个问题, 1.触发这事件的效果,是需要在鼠标起来的时候触发。 2.鼠标起来的时候,如果被选中的包含太多了。比如多个元素,则不显示操作 简单版本就只有这两点,更复杂的效果是还要考虑类似‘ctrl’+‘A’时的情况 对于上述问题,第一点,使用
依赖于emoji 库,主要是雪碧图实现表情的统一。 采用div标签的contenteditable属性实现编辑功能。 难点在于选择表情时的光标位置保存。实现任意光标位置插入表情。 实现一个小小的demo供大家参考, 共同学习!
可以使用 JavaScript 中的 selectionStart 和 selectionEnd 属性来指定光标位置。 这些属性属于 HTMLInputElement 对象,因此你需要首先将你的输入元素转换为这种类型,然后就可以使用这些属性了。 const input = document.getElementById('myInput'); input.selectionStart = 2; input.selectionEnd = 4; 这样就会将光标移动到输入字段的第 2 到第 4 个字符的位置。 注意:在使用这些属性之前,你应该确保输入字段是可编辑的(即具有 "contenteditable" 属性)。