最近接到了一个业务需求,让用户可以经过网页聊天框的方式在线完成交易,一个用户可能有多个业务群,其中一个功能就是要@人,@这个功能在现实的应用中常常能够遇到,好比微博、QQ都有@功能,今天咱们就之前端的方式谈谈怎么一步步实现一个@功能。html
obj.selectionStart获取光标位置前端
obj.setSelectionRange(n, n)设置光标位置git
keyup事件和keydown事件github
几个地方特别说明下:实际操做中,咱们出现了@选框要实时更新列表数据,在这个dome中咱们先用静态列表代替,效果是同样的。而后这个pre是用来定位@选框用的,注意pre大小,字体要和输入框同样,并将pre绝对定位到页面的左上角,并设置不可见。ajax
<!-- 文本输入框 --> <textarea id="app" class="con" contenteditable="true"></textarea> <!-- 提交按钮 --> <input type="button" class="submit" id="submit" value="提交"> <!-- @选框 --> <div id="selectuser" class="selectbox" style="display:none;"> <h2>@用户</h2> <ul id="selectlist"> <li uid="1">陆小凤</li> <li uid="2">西门吹雪</li> <li uid="3">百晓生</li> <li uid="4">张无忌</li> <li uid="5">赵敏</li> <li uid="6">段誉</li> <li uid="7">虚竹</li> <li uid="8">段德</li> <li uid="9">周杰伦</li> <li uid="10">张学友</li> </ul> </div> <!-- 暂存输入框数据 --> <pre id="pre_text"></pre>
具体实现思路:检测键盘的左边是不是@字符,若是有的话,将输入框光标前面的内容复制一份到pre,并在pre后面增长一个span,这个sapn用来协助定位@选框的。咱们算出这个span相对于页面左上角的left和top,就是等下@选框相对于文本框的left和top的距离,由于咱们@选框是绝对定位相对于body,因此在加上文本框相对于body的offsetLeft和offsetTop就是咱们@选框所要定位的left和top了。数组
//全局定义一个变量为光标位置 var cursor; //文本框绑定keyup事件,检测输入 textapp.addEventListener('keyup', function(e){ //获取光标 cursor = textapp.selectionStart; // 当前光标所在位置的前一位为@字符,出现@选框 if(textapp.value.substring(0,cursor).charAt(cursor-1) === '@'){ // 判断最后一个字符是否为@ pre_text.innerHTML = textapp.value.substring(0,cursor); pre_text.innerHTML += '<span id="proxy" style="display:inline-block; width: 100px;"></span>'; var span = document.getElementById('proxy'); var conX = textapp.offsetLeft; var conY = textapp.offsetTop; var spanX = span.offsetLeft + conX; var spanY = span.offsetTop + conY; selectuser.style.left = spanX + 'px'; selectuser.style.top = spanY + 'px'; selectuser.style.display = 'block'; //设置@选框的默认样式 listSet(); }else{ selectuser.style.display = 'none'; } }) // @框默认设置 function listSet() { var list = $('#selectlist'); list.focus(); $('#selectlist').find('li').eq(0).addClass('hover').siblings('li').removeClass('hover'); $('#selectuser').scrollTop(0); }
当咱们的@选框出现了,而且定位好了,出如今咱们想要的位置了,咱们直接用键盘上下去选择所要@的人了(鼠标点击选中状况等下介绍)。这里咱们要考虑的点有两个:1.当咱们光标在输入框最后,咱们按上下左右光标就会变化位置。2.选择以后光标位置的变化。app
1的解决办法是:咱们光标位置的变化是在keydown的时候执行的,keydown是先于咱们的keyup以前执行的,因此咱们就要在keydown的时候就阻止默认,防止光标移动dom
textapp.addEventListener('keydown', function(e){ //创建在@选框出现的状况下 if(selectuser.style.display == 'block'){ var code = e.keyCode; //左右回车时阻止默认,防止光标移动 if(code == 38 || code == 40 || code == 13){ e.preventDefault(); } } })
2.选中@人后,咱们用setSelectionRange来设置光标的位置,将下面这段代码输入框keyup绑定事件里面,放在最前面ide
// 当@选框存在时,判断键盘上移,下移,以及回车选中事件 if(selectuser.style.display == 'block'){ var code = e.keyCode; if(code == 38){ // 上移 preCode(); return; }else if (code == 40){ // 下移 nextCode(); return; }else if(code == 13){ //回车选中@人 var textname = ''; $('#selectlist').find('li').each(function(){ if($(this).hasClass('hover')){ textname = $(this).html(); } }); //@完后文本框显示内容 $('#app').val(getText($('#app').val(), cursor, textname)); //添加后光标的位置 var n = textname.length + 1 + cursor; //设置光标的位置 textapp.setSelectionRange(n, n); //选中后隐藏@选框 $('#selectuser').hide(); return; } }
上面这段代码咱们用到了三个函数函数
// 键盘上移 function preCode() { var index = $('#selectlist').find('.hover').index(); if(index == 0){ return; }else{ index--; $('#selectuser').scrollTop(index * 26); $('#selectlist').find('li').eq(index).addClass('hover').siblings('li').removeClass('hover'); } } // 键盘下移 function nextCode() { var len = $('#selectlist').find('li').length; var index = $('#selectlist').find('.hover').index(); if(index == len-1){ return; }else{ index++; $('#selectuser').scrollTop(index * 26); $('#selectlist').find('li').eq(index).addClass('hover').siblings('li').removeClass('hover'); } } //@人的文本格式,为后面加一个空格,后面用到 function getText(app, cursor, textname) { var text1 = app.substring(0, cursor); var text2 = app.substring(cursor); return text1 + textname + ' ' + text2; }
当咱们消息输入完成后,点击发送(咱们这里用个提交按钮)。咱们要检测这个消息中是否有@人,并把当前这条消息有效的@人取出来,这里注意并非说咱们以前选中了@某我的后就有效了,可能在这我的的名字中我又输入了其余的字符。因此咱们要在发送消息的时候作一次检查,把有效的@人提取出来,而且之后台规定的数据格式。(咱们暂且规定为数组吧)。
// 提交 $('#submit').on('click', function() { var msg = $('#app').val(); //检测输入框是否为空 if(msg === ''){ alert('内容不能为空!'); return; } //返回有效@人列表 var arr = handleMsg(msg); }); //操做信息提取有效@人 function handleMsg(msg) { //存放有效@人id的数组 var At = []; //正则验证吧以@开头空格结束的选出来已数组的形式 var arrAt = msg.match(/@{1}([\u4e00-\u9fa5]|\w)+\s{1}/g); //说明没有@人,直接韩慧 if(arrAt === null){ console.log('没有选中@的人!'); return At; } // 对arrAt数组即当前信息@人的列表进行遍历 for (var i = 0; i < arrAt.length; i++) { var username = arrAt[i].replace('@', '').trim(); // 对比当前群组人选 var grounpuser = $('#selectlist').find('li'); for (var j = 0; j < grounpuser.length; j++) { //若是名字相同,则把id放进数组内容 if(username == grounpuser.eq(j).html()){ var uid = grounpuser.eq(j).attr('uid'); At.push(uid); break; } }; }; return At; }
好了,一个@的功能已经基本实现了,剩下的就是经过ajax与后台的交互了。若是你以为本篇文章对你有收获请赞下,也能够关注下我,分享工做,学习的前端我的感悟分享。github