Javascript设置和获取文本框鼠标位置

最近在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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值