如何实现textarea中输入@在当前文本的右下方出现一个div,里面选择人名

如何实现textarea中输入@在当前文本的右下方出现一个div,里面选择人名

问题描述:

我想实现一个效果就是在textarea中输入一个@然后在该文字的右下方出现一个div,里面是放一个列表的,跟QQ的输入一样,不管是复制还是直接输入的@都出现这个功能!(前两天回答的那些有bug的)图片说明

亲自试了下,应该是上取整。
你看这个可不可以,有什么问题可以私信我。

 <!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="100" 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);
            //console.log(position,(ipt.value+'').length)
            //如果光标在文本最后面,且最后一个是@
            if((position == (ipt.value+'').length) && /@$/.test(ipt.value)){
                var iStyle = window.getComputedStyle(ipt);
                //把双字节的替换成两个单字节的然后再获得长度 
                var len = (ipt.value || '').replace(/[^\x00-\xff]/g,"01").length/2;
                var fz = parseFloat(iStyle.fontSize);
                var wd = parseFloat(iStyle.width);
                var lh = parseFloat(iStyle.lineHeight);
                list.style.left = fz*(len%wd)>wd?wd:fz*(len%wd) + "px";
                list.style.top = Math.ceil(len/wd)*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>

https://github.com/yuku-t/jqu...
https://github.com/ichord/At.js (建议用这个,bug少,但不是专为Vue适配)
https://github.com/fritx/vue-at 可以参考一下,里面有源码

https://github.com/fritx/vue-at 可以参考一下,里面有源码

能不能给多行文本框添加一个事件获取文本框内容,然后用正则去匹配这个内容,匹配成功就把div设置为显示啊。

<!doctype html>



Document
<br> *{padding:0;margin:0;}<br> .box{position:relatuve;}<br> #ipt{<br> font-size:16px;<br> padding-left:5px;<br> height:30px;<br> line-height:30px;<br> }<br> #list{<br> position:absolute;<br> list-style:none;<br> width:150px;<br> display:none;<br> }<br> #list li{height:25px;line-height:25px;}<br> #list li:hover{background:#efefef;cursor:pointer;}<br>





  • qq.com
  • sina.com
  • 163.com


<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>


网上看到一个实现 还不错 基本满足你的要求 你在改一改就行了

可以用正则判断@,当出现@就显示一个下拉(有multiple属性的)或者直接一个下拉,选择完后再隐藏

js获取textbox焦点事件,当输入@符号时,用ajax调用后台方法,获取查询数据,组织成下拉框数据。

通过javascript 或jquery ,结合注册键盘事件实现。

你之前的问题是我回答的,上面那个贴代码的贴的也是我的代码,有bug可以私信我,没必要在花一次钱。
之前我是用输入框写的,不是文本域,所以少了一步,你在计算下文本域的宽度,用文字总长度除宽度,除数下取整就是行数,行数乘行高就是 列表 的top值,加上这个就可以了。
文字总长度模宽度的值就是 列表的 left值。

<!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>

keyDown 事件,可以查一下@ 符号是那个。按键=@的时候弹出div