業務開發情境之:實現一個@功能

最近接到了一個業務需求,讓用戶可以經過網頁聊天框的方式在線完成交易,一個用戶可能有多個業務羣,其中一個功能就是要@人,@這個功能在現實的應用中常常能夠遇到,好比微博、QQ都有@功能,今天咱們就之前端的方式談談怎麼一步步實現一個@功能。html

@功能涉及到的原生API

  • obj.selectionStart獲取光標位置前端

  • obj.setSelectionRange(n, n)設置光標位置git

  • keyup事件和keydown事件github

1.搭建咱們的html文件

幾個地方特別說明下:實際操做中,咱們出現了@選框要實時更新列表數據,在這個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);
}

3.鍵盤直接操做@選框

當咱們的@選框出現了,而且定位好了,出如今咱們想要的位置了,咱們直接用鍵盤上下去選擇所要@的人了(鼠標點擊選中狀況等下介紹)。這裏咱們要考慮的點有兩個: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;
    }

4.提交操做時,取出有效的@人

當咱們消息輸入完成後,點擊發送(咱們這裏用個提交按鈕)。咱們要檢測這個消息中是否有@人,並把當前這條消息有效的@人取出來,這裏注意並非說咱們以前選中了@某我的後就有效了,可能在這我的的名字中我又輸入了其餘的字符。因此咱們要在發送消息的時候作一次檢查,把有效的@人提取出來,而且之後臺規定的數據格式。(咱們暫且規定爲數組吧)。

// 提交
    $('#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

相關文章
相關標籤/搜索