最近接到了一個業務需求,讓用戶可以經過網頁聊天框的方式在線完成交易,一個用戶可能有多個業務羣,其中一個功能就是要@人,@這個功能在現實的應用中常常能夠遇到,好比微博、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