最近在csdn问答板块看到了一个问题:
如何实现textarea中输入@在右下方出现一个提示框?
主要难点是光标所在的位置,网上找了下,大多是获取光标所在的字符位数,而不是距离开头的宽高,所以舍弃。
但是本文还是需要这个技术,来判断光标是不是在文本最后。
//输入框获取光标
function getPosition(element) {
var cursorPos = 0;
if (document.selection) {//IE
var selectRange = document.selection.createRange();
selectRange.moveStart('character', -element.value.length);
cursorPos = selectRange.text.length;
} else if (element.selectionStart || element.selectionStart == '0') {
cursorPos = element.selectionStart;
}
return cursorPos;
}
新思路:计算文本中有多少和字节,2个字节为一个字,根据文本的字体大小和字数获取到文本的长度,由这个长度再根据所处环境计算提示框的位置。
所处环境指的是该元素所在位置,光标相对于文本域所在位置(根据总长度和文本域宽度判断在光标第几行的哪个位置))。
下面是一个简单的demo,是以输入框为例,相比文本域简单很多。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{padding:0;margin:0;}
.box{position:relatuve;}
#ipt{
font-size:16px;
padding-left:5px;
height:30px;
line-height:30px;
}
#list{
position:absolute;
list-style:none;
width:150px;
display:none;
}
#list li{height:25px;line-height:25px;}
#list li:hover{background:#efefef;cursor:pointer;}
</style>
</head>
<body>
<div class='box'>
<input type="text" id='ipt'>
<ul id='list'>
<li>qq.com</li><li>sina.com</li><li>163.com</li>
</ul>
</div>
<script>
var ipt = document.getElementById('ipt');
var list = document.getElementById('list');
ipt.oninput = function(e){
//console.log(e)
//获取光标位置
var position = getPosition(ipt);
console.log(position,(ipt.value+'').length)
//如果光标在文本最后面,且最后一个是@
if((position == (ipt.value+'').length) && /@$/.test(ipt.value)){
//把双字节的替换成两个单字节的然后再获得长度
var len = (ipt.value || '').replace(/[^\x00-\xff]/g,"01").length/2;
var fz = parseFloat(window.getComputedStyle(ipt).fontSize);
var wd = parseFloat(window.getComputedStyle(ipt).width);
list.style.left = fz*len>wd?wd:fz*len + "px";
list.style.display = "block";
}else{
list.style.display = "none";
}
}
for(var i=0;i<list.children.length;i++){
list.children[i].onclick = function(e){
ipt.value += e.target.innerHTML;
list.style.display = "none";
}
}
//输入框获取光标
function getPosition(element) {
var cursorPos = 0;
if (document.selection) {//IE
var selectRange = document.selection.createRange();
selectRange.moveStart('character', -element.value.length);
cursorPos = selectRange.text.length;
} else if (element.selectionStart || element.selectionStart == '0') {
cursorPos = element.selectionStart;
}
return cursorPos;
}
</script>
</body>
</html>
增加文本域的案例
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{padding:0;margin:0;}
.box{position:relatuve;}
#ipt{
font-size:16px;
padding-left:5px;
line-height:30px;
}
#list{
position:absolute;
list-style:none;
width:150px;
display:none;
}
#list li{height:25px;line-height:25px;}
#list li:hover{background:#efefef;cursor:pointer;}
</style>
</head>
<body>
<div class='box'>
<textarea rows="3" cols="20" id='ipt'></textarea>
<ul id='list'>
<li>qq.com</li><li>sina.com</li><li>163.com</li>
</ul>
</div>
<script>
var ipt = document.getElementById('ipt');
var list = document.getElementById('list');
ipt.oninput = function(e){
//console.log(e)
//获取光标位置
var position = getPosition(ipt);
ipt.value = ipt.value || '';
//如果光标后面是空格或没有内容,且光标前面最后一个是@
var s = ipt.value.charAt(position)
if((s == "" || s == " ") && ipt.value.charAt(position-1) == "@"){
var iStyle = window.getComputedStyle(ipt),
fz = parseFloat(iStyle.fontSize),//字体大小
wd = parseFloat(iStyle.width),//文本域宽度
lh = parseFloat(iStyle.lineHeight),//行高
pd = parseFloat(iStyle.paddingLeft),//左内边距
newStr = ipt.value.substr(0,position+1),
//有换行符根据换行符拆分
valArr = newStr.indexOf("\n")!==-1 ? newStr.split("\n") : [ipt.value];
for(var i=0,j=0;i<valArr.length;i++){
//把双字节的替换成两个单字节的然后再获得长度
var len = valArr[i].replace(/[^\x00-\xff]/g,"01").length/2;
j += Math.ceil((len*fz)/wd);
}
list.style.left = (len*fz)%wd==0?wd:(len*fz)%wd + pd + "px";
list.style.top = j*lh + "px";
list.style.display = "block";
}else{
list.style.display = "none";
}
}
for(var i=0;i<list.children.length;i++){
list.children[i].onclick = function(e){
ipt.value += e.target.innerHTML;
list.style.display = "none";
}
}
//输入框获取光标
function getPosition(element) {
var cursorPos = 0;
if (document.selection) {//IE
var selectRange = document.selection.createRange();
selectRange.moveStart('character', -element.value.length);
cursorPos = selectRange.text.length;
} else if (element.selectionStart || element.selectionStart == '0') {
cursorPos = element.selectionStart;
}
return cursorPos;
}
</script>
</body>
</html>