前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TextRange之插入表情

TextRange之插入表情

作者头像
meteoric
发布2019-02-25 16:50:29
1.2K0
发布2019-02-25 16:50:29
举报
文章被收录于专栏:游戏杂谈

SNS类或是微博类的产品一般都有一个功能:插入表情,如下所示:

重点:兼容IE与其它主流的浏览器,根据上一次选择的选区范围进行操作。

自己写了一个TextRange(参考了网上的一些例子和代码)

代码语言:javascript
复制
/**
 * @author Meteoric_cry
 */

/**
 * 文本选区操作类
 */
var TextRange = function() {
	var inner;
	
	return inner = {
		/**
		 * 获取选区
		 * 
		 * @param {HTMLElement} oElement input或是textarea对象
		 * @return [start, end] 返回input或textarea选区的开始与结束的索引值
		 */
		getRange : function(oElement) {
			var start = 0, end = 0;
			
			if(!document.selection) {//not IE
				start = oElement.selectionStart;
				end = oElement.selectionEnd;
			} else if(document.selection) {
				var range = document.selection.createRange(),
					range_all = document.body.createTextRange(),
					i = 0;
				
				
				range_all.moveToElementText(oElement);
				/**
				 * 两个range:一个是已经选择的text(range),一个是整个textarea(range_all)
				 * 
				 * compareEndPoints比较两个端点,range_all的起点比range更向左(allIndex - index < 0),则range_all需要向右移动
				 */
				for(; range_all.compareEndPoints("StartToStart", range) < 0; start++) {
					range_all.moveStart('character', 1);
				}
				
				for(; i<start; i++) {
					if(oElement.value.charAt(i) == "\n") {
						start++;
					}
				}
				
				range_all = document.body.createTextRange();
				range_all.moveToElementText(oElement);
				
				for(; range_all.compareEndPoints('StartToEnd', range) < 0; end++) {
					range_all.moveStart('character', 1);
				}
				
				for(i=0; i <= end; i++) {
					if(oElement.value.charAt(i) == "\n") {
						end++;
					}
				}
			}
			
			return [start, end];
		},	
		/**
		 * 获取选区的起始位置
		 * 
		 * @param {HTMLElement} oElement input或是textarea对象
		 * @return DOM对象选区的起始位置
		 */
		selectionStart : function(oElement) {
			return inner.getRange(oElement)[0];
		},
		/**
		 * 获取选取前的内容
		 * 
		 * @param {HTMLElement} oElement input或是textarea对象
		 * @return 返回DOM对象选区开始前的文本内容
		 */
		selectionBefore : function(oElement) {
			 return oElement.value.slice(0, inner.getRange(oElement)[0]);
		},
		/**
		 * 设置DOM的选区
		 * 
		 * @param {HTMLElement} oElement input或是textarea对象
		 * @param {Number} start 被设置的选区的起始位置 
		 * @param {Number} end	被设置的选区的结束位置
		 */
		selectText : function(oElement, start, end) {
			oElement.focus();
			
	        if (!document.selection) {
	            oElement.setSelectionRange(start, end);
	            return ;
	        }
	        var range = oElement.createTextRange();
	        range.collapse(1);
	        range.moveStart("character", start);
	        range.moveEnd("character", end - start);
	        range.select();
		},
		/**
		 * 插入文本内容
		 * 
		 * @param {HTMLElement} oElement
		 * @param {String} sInsertText
		 * @param {Number} nStart
		 * @param {Number} nLen
		 */
		insertText : function(oElement, sInsertText, nStart, nLen) {
			oElement.focus();
	        nLen = nLen || 0;
			
	        if (!document.selection) {
	            var text = oElement.value,
	                start = nStart - nLen,
	                end = start + sInsertText.length;
				
	            oElement.value = text.slice(0, start) + sInsertText + text.slice(nStart, text.length);
	            it.selectText(oElement, end, end);
	            return ;
	        }
	        var c = document.selection.createRange();
	        c.moveStart("character", -nLen);
	        c.text = sInsertText;
		},
		/**
		 * 获取光标的位置
		 * 
		 * @param {HTMLElement} oElement
		 * @return cursorPos
		 */
		getCursorPos : function(oElement) {
			var cursorPos = 0;
			
	        if (window.ActiveXObject) {
	            oElement.focus();
	            var range = document.selection.createRange(),
					stored_range = range.duplicate();
	           	
	            stored_range.moveToElementText(oElement);
	            stored_range.setEndPoint("EndToEnd", range);
	            oElement.selectionStart = stored_range.text.length - range.text.length;
	            oElement.selectionEnd = oElement.selectionStart + range.text.length;
	            cursorPos = oElement.selectionStart;
	        } else {
	            if (oElement.selectionStart || oElement.selectionStart == "0") {
	                cursorPos = oElement.selectionStart;
	            }
	        }
			
	        return cursorPos;
		},
		/**
		 * 获取选区内的文本内容
		 * 
		 * @param {HTMLElement} oElement
		 * @return selectedText 选区的文本内容
		 */
		getSelectedText : function(oElement) {
			var selectedText = "";
			
	        var getSelection = function (e) {
	            if (e.selectionStart != undefined && e.selectionEnd != undefined) {
	                return e.value.slice(e.selectionStart, e.selectionEnd);
	            } else {
	                return "";
	            }
	        };
			
	        if (window.getSelection) {
	            selectedText = getSelection(oElement)
	        } else {
	            selectedText = document.selection.createRange().text;
	        }
	        return selectedText;
		},
		/**
		 * 设置光标的位置,默认不选区
		 * 
		 * @param {HTMLElement} oElement
		 * @param {Number} pos
		 * @param {Number} coverlen
		 */
		setCursor : function(oElement, pos, coverlen) {
			pos = pos ? pos : oElement.value.length;
			coverlen = coverlen ? coverlen : 0;
	        oElement.focus();
			
	        if (oElement.createTextRange) {
	            var range = oElement.createTextRange();
	            range.move("character", pos);
	            range.moveEnd("character", coverlen);
	            range.select();
	        } else {
	            oElement.setSelectionRange(pos, pos + coverlen);
	        }
		},
		/**
		 * 插入内容后光标的位置保持不变
		 * 
		 * @param {HTMLElement} oElement  
		 * @param {String} str
		 * @param {Object} pars
		 */
		unCoverInsertText : function(oElement, str, pars) {
			pars = pars ? pars : {};
	        pars.start =  pars.start ? pars.start * 1 : 0;
	        pars.end = pars.end ? pars.end * 1 : oElement.value.length;
			
	        var text = oElement.value,
	            fstr = text.slice(0, pars.start),
	            lstr = text.slice(pars.end, text == "" ? 0 : text.length);
			
			oElement.value = fstr + str + lstr;
			
	        inner.setCursor(oElement, pars.start + (str ? str.length : 0));
		}
	}
}();

先写个例子测试一下TextRange里面的方法:

代码语言:javascript
复制
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>选区的测试</title>
<script type="text/javascript" src="textRange.js"></script>
</head>
<body>

<table cellpadding="0" cellspacing="0" style="border:1px solid #406c99;">
	<tbody>
		<tr>
			<td>start:<input type="text" id="start" /></td>
			<td>end:<input type="text" id="end" /></td>
		</tr>
		<tr>
			<td colspan="2">
				<textarea id="txt" style="width:400px; height:100px;"  onkeyup="savePos(this);"  onmouseup="savePos(this);" onfocus="savePos(this);"></textarea>
			</td>
		</tr>
		<tr>
			<td><input type="text" id="insTxt" /></td>
			<td><input type="button" onclick="addText();" value="addText" /></td>
		</tr>
	</tbody>
</table>


<div>
	<button onclick="setSelection();">选中选区</button>
	<button onclick="setCursorPos();">设置光标位置</button>
</div>

<div style="border:1px solid #999; width:800px; margin-top:30px;">
	选区之前的内容:<input type="text" id="beforeTxt"	style="width:600px;"/>
</div>

<script type="text/javascript">
	function $(id) {
		return typeof id === "string" ? document.getElementById(id) : id;
	}
	
	//添加内容
	function addText() {
		var elem = $("txt");
		var range = elem.getAttribute('range') ? elem.getAttribute('range').split("|") : [0, 0];
		var str_1 = elem.value.slice(0, range[0]);
		var str_2 = elem.value.slice(range[1]);
		
		elem.value = str_1 + $("insTxt").value + str_2;
	}
	
	//保存选区
	function savePos(elem) {
		var range = TextRange.getRange(elem);
		
		$("start").value = range[0];
		$("end").value = range[1];
		
		var rangeBeforeTxt = TextRange.selectionBefore(elem);
		$("beforeTxt").value = rangeBeforeTxt.replace(/\n/g, '--');
		
		elem.setAttribute("range", range.join("|"));
	}
	
	//设置选区
	function setSelection() {
		var start = $("start").value,
			end = $("end").value;
			
		TextRange.selectText($("txt"), start, end);
		
		TextRange.unCoverInsertText($("txt"), '#===#', {
            start: start,
            end: end
        })
	}
	
	function setCursorPos() {
		TextRange.setCursor($("txt"), 3, 5);//索引值、长度
	}
</script>

</body>
</html>

博客园插入代码好像有问题,复制到本地运行测试一下就行了 :)

下面就是插入表情的示例代码了:

代码语言:javascript
复制
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>UBB表情的插入</title>
<script type="text/javascript" src="textRange.js"></script>
<style type="text/css">
	* {margin:0; padding:0;}
	body {font:12px/1.3 Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
	ul, li {list-style:none}
	img {border:none}
	
	.container {margin:30px;}
	#txtDemo {width:475px; height:110px; word-break:break-all; word-wrap:break-word;}
	#facePanel {border-width:1px 2px 2px 1px; border-color: #CCCCCC; border-style:solid; -webkit-border-radius: 6px; -moz-border-radius:6px; padding:6px; width:330px; margin-top:5px; display:none;}
	#facePanel li{float:left; width:28px; height:28px; padding:0 5px 5px 0;}
	#facePanel li a {display:block; text-decoration:none; border:1px dashed #DDD; width:26px; height:26px; line-height:26px; overflow:hidden; text-align:center;}
	#facePanel li a:hover {border-color:#999;}
	
	#facePanel li a span {display:inline-block;}
	#facePanel li a img {vertical-align:middle;}
	
	#facePanel ul {zoom:1;}
	#facePanel ul:after{ content:"\0020"; display:block; height:0; line-height:0; clear:both; visibility:hidden;}
</style>
</head>
<body>
	
<div class="container">
	<div>
		<textarea id="txtDemo"></textarea>
	</div>
	<button onclick="showFace(event);">插入表情</button>
	<div id="facePanel">sadf</div>
</div>

<script type="text/javascript">
	function $(id) {
		return typeof id === 'string' ? document.getElementById(id) : id;
	}
	
	function addEvent(el, type, handler) {
		if(el.attachEvent) {
			el.attachEvent("on" + type, handler);
		} else if(el.addEventListener) {
			el.addEventListener(type, handler, false);
		}
	}
	
	function removeEvent(el, type, handler) {
		if(el.detachEvent) {
			el.detachEvent('on' + type, handler);
		} else if(el.removeEventListener) {
			el.removeEventListener(type, handler, false);
		}
	}
	
	var faceInited = false;
	
	//显示表情
	function showFace(ev) {
		if(!faceInited) {
			initFace();
		}
		
		var facePanel= $("facePanel");
		
		facePanel.style.display = "block";
		addEvent(document.body, 'click', hideFace);
		addEvent(facePanel, 'click', cancelEventBubble);
		
		cancelEventBubble(ev);
	}
	
	//隐藏表情
	function hideFace() {
		$("facePanel").style.display = "none";
		removeEvent(document.body, 'click', hideFace);
		removeEvent($("facePanel"), 'click', cancelEventBubble);
	}
	
	//插入表情
	function insertFace(elem) {
		var txtElem = $("txtDemo"),
			range = txtElem.getAttribute("range") ? txtElem.getAttribute("range").split("|") : [0, 0];
		
		var str_1 = txtElem.value.slice(0, range[0]);
		var str_2 = txtElem.value.slice(range[1]);
		
		txtElem.value = str_1 + elem.getAttribute("value") + str_2;
		
		if(!document.selection) {
			txtElem.selectionStart = txtElem.value.length;
			txtElem.selectionEnd = txtElem.value.length;
		} else {
			var range = txtElem.createTextRange();
	        range.collapse(1);
	        range.moveStart("character", txtElem.value.length);
	        range.moveEnd("character", txtElem.value.length);
	        range.select();
		}
		
		txtElem.focus();
		
		hideFace();
	}
	
	//取消事件冒泡
	function cancelEventBubble(ev) {
		ev = ev || window.event;
		
		if(ev.stopPropagation) {
			ev.stopPropagation();
		} else if(!ev.cancelBubble) {
			ev.cancelBubble = true;
		}
	}
	
	//记录textarea的选区的start&end
	function savePos() {
		var elem = $("txtDemo"),
			range = getRange(elem);//获取选区
		
		elem.setAttribute("range", range.join("|"));
		
		document.title = "start:" + range[0] + "--" + "end:" + range[1];
		
		cancelEventBubble(arguments[0] || window.event);
	}
	
	!(function() {
		var txtElem = $("txtDemo");
		
		addEvent(txtElem, 'focus', savePos);
		addEvent(txtElem, 'mouseup', savePos);
		addEvent(txtElem, 'keyup', savePos);
		addEvent(txtElem, 'mousemove', savePos);//Chrome 在选中文本域内的文字时,不能触发mouseup事件,导致range依旧为最近一次的range
	})();
	
	//初始化表情
	function initFace() {
		var faces = [{"icon":"\u8db3\u7403","value":"[\u8db3\u7403]","src":"basic\/football.gif"},{"icon":"\u54e8\u5b50","value":"[\u54e8\u5b50]","src":"basic\/shao.gif"},{"icon":"\u7ea2\u724c","value":"[\u7ea2\u724c]","src":"basic\/redcard.gif"},{"icon":"\u9ec4\u724c","value":"[\u9ec4\u724c]","src":"basic\/yellowcard.gif"},{"icon":"\u54c8\u54c8","value":"[\u54c8\u54c8]","src":"basic\/laugh.gif"},{"icon":"\u5475\u5475","value":"[\u5475\u5475]","src":"basic\/smile.gif"},{"icon":"\u6cea","value":"[\u6cea]","src":"basic\/cry.gif"},{"icon":"\u6c57","value":"[\u6c57]","src":"basic\/sweat.gif"},{"icon":"\u7231\u4f60","value":"[\u7231\u4f60]","src":"basic\/love.gif"},{"icon":"\u563b\u563b","value":"[\u563b\u563b]","src":"basic\/tooth.gif"},{"icon":"\u54fc","value":"[\u54fc]","src":"basic\/hate.gif"},{"icon":"\u5fc3","value":"[\u5fc3]","src":"basic\/heart.gif"},{"icon":"\u6655","value":"[\u6655]","src":"basic\/dizzy.gif"},{"icon":"\u6012","value":"[\u6012]","src":"basic\/angry.gif"},{"icon":"\u86cb\u7cd5","value":"[\u86cb\u7cd5]","src":"basic\/cake.gif"},{"icon":"\u82b1","value":"[\u82b1]","src":"basic\/flower.gif"},{"icon":"\u6293\u72c2","value":"[\u6293\u72c2]","src":"basic\/crazy.gif"},{"icon":"\u56f0","value":"[\u56f0]","src":"basic\/sleepy.gif"},{"icon":"\u5e72\u676f","value":"[\u5e72\u676f]","src":"basic\/cheer.gif"},{"icon":"\u592a\u9633","value":"[\u592a\u9633]","src":"basic\/sun.gif"},{"icon":"\u4e0b\u96e8","value":"[\u4e0b\u96e8]","src":"basic\/rain.gif"},{"icon":"\u4f24\u5fc3","value":"[\u4f24\u5fc3]","src":"basic\/sad.gif"},{"icon":"\u6708\u4eae","value":"[\u6708\u4eae]","src":"basic\/moon.gif"},{"icon":"\u732a\u5934","value":"[\u732a\u5934]","src":"basic\/pig.gif"},{"icon":"\u8721\u70db","value":"[\u8721\u70db]","src":"basic\/candle.gif"}];
		var imgURI = "http://timg.sjs.sinajs.cn/miniblog2style/images/common/face/";
		var tempArr = [];
		tempArr.push('<ul>');
		
		for(var i=0, len = faces.length; i<len; i++) {
			tempArr.push([
				'<li><a href="javascript:;" hideFocus="true" onclick="insertFace(this);return false;" value="' + faces[i].value + '" title="' + faces[i].icon + '"><img src="' + imgURI + faces[i].src + '" alt="' + faces[i].icon + '" /><span>&nbsp;</span></a></li>',
			].join(""));
		}
		
		tempArr.push('</ul>');
		
		$("facePanel").innerHTML = tempArr.join("");
	}
	
	//获取选区
	function getRange(elem) {
		var start = 0, end = 0;
			
		if(!document.selection) {
			start = elem.selectionStart;
			end = elem.selectionEnd;
		} else if(document.selection) {
			var range = document.selection.createRange(),
				range_all = document.body.createTextRange(),
				i = 0;
				
			range_all.moveToElementText(elem);
			
			for(; range_all.compareEndPoints("StartToStart", range) < 0; start++) {
				range_all.moveStart('character', 1);
			}
			
			for(; i<start; i++) {
				if(elem.value.charAt(i) == "\n") {
					start++;
				}
			}
			
			range_all = document.body.createTextRange();
			range_all.moveToElementText(elem);
			
			for(; range_all.compareEndPoints('StartToEnd', range) < 0; end++) {
				range_all.moveStart('character', 1);
			}
			
			for(i=0; i <= end; i++) {
				if(elem.value.charAt(i) == "\n") {
					end++;
				}
			}
		}
		
		return [start, end];
	}
</script>

</body>
</html>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2010-10-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档