1. 程式人生 > >實現動態輸入關鍵字時關鍵字高亮

實現動態輸入關鍵字時關鍵字高亮

專案中要求實現一個功能,在輸入框中輸入特定的搜尋語句,當輸入為關鍵字時,關鍵字高亮,且輸入滿一行進行換行操作

首先分析如果想實現一部分關鍵字高亮,輸入框本身肯定是做不到的,因為實現高亮需要通過動態的給關鍵字新增span標籤,再給span標籤中的內容設定顏色

如果使用div,那必須給div新增contenteditable = "true"屬性,使其div可輸入,其次監聽按鍵是否擡起,對div中的內容進行檢測並替換關鍵字,我在嘗試這種方法時遇到了幾個問題,第一個問題是每次輸入內容進行替換後游標自動定位在開頭,此問題在網上查詢資料解決如下

function po_Last_Div(obj) {

    if (window.getSelection) {//ie11 10 9 ff safari

        obj.focus(); //解決ff不獲取焦點無法定位問題

        var range = window.getSelection();//建立range

        range.selectAllChildren(obj);//range 選擇obj下所有子內容

        range.collapseToEnd();//游標移至最後

    }

else if (document.selection) {//ie10 9 8 7 6 5

        var range = document.selection.createRange();//建立選擇物件

        //var range = document.body.createTextRange();

        range.moveToElementText(obj);//range定位到obj

        range.collapse(false);//游標移至最後

        range.select();

    }

}

第二個問題為如果使用者將關鍵字改變,但程式進行監聽時獲取的還是加了span標籤的內容,所以當關鍵字被修改成不是關鍵字時,其高亮並沒有消失,此問題的解決辦法就是每次監聽到有鍵按下,獲取div的文字值(div.text()),然後使用replace()方法將獲取到的文字值中的空格替換成&nbsp(這塊的替換因為在查詢關鍵字時要利用正則表示式,正則表示式中有&nbsp),再根據需求中對關鍵字的定義進行各種匹配與替換。在顯示的時候用html()方法讓瀏覽器對一些標籤進行轉化

第三個問題是當輸入中文時在虛擬按鍵中,應用程式同樣監聽按鍵,所以中文輸入時會出現來回跳轉,並把中文輸入未結束的拼音同樣顯示在頁面上,此問題的原因主要是因為我通過監聽按鍵來判斷內容修改,至此未找到能很好解決此問題的方法,畢竟還是前端小白一枚。

這條路走死後,我又回到原專案中,研究其實現原理,和該原理出現的bug

原專案中實現的原理,大邏輯是使用angularjs將一個輸入框和div繫結,輸入框使用ng-bind將值傳遞給應用程式控制器,之後對輸入框的值進行處理(關鍵字實現高亮),然後將div新增ng-bind-html屬性(用於顯示關鍵字高亮的內容),最後將改變後的內容顯示在介面

在這過程中,讓輸入框中的內容透明,在輸入框中的上層有div,使用者看到的是div顯示出來的帶有高亮的內容,但是實際操作的是下面被設定為透明顏色的輸入框

在此方法的實現過程中,會出現三個bug

第一、當輸入中文時,虛擬輸入內容不顯示,看不到輸入的拼英,只有字,分析出現此問題的原因是因為輸入框和div進行繫結是值的繫結,所以當輸入中文時,只有我們的值才會被傳遞,拼英不會顯示

第二、因為輸入框的字型間隔和div中顯示的字型間隔不一樣,當輸入過多內容的時候,輸入框的游標會和div輸入的值重疊(雖然輸入框的內容設定為透明,但游標還可以看見,所以div是沒有游標的,是用input游標,div的內容)

第三、當用戶在輸入一段值後又想在中間插入值時,這時又出現了問題,input輸入框的游標會動來動去,這時input框中游標位置的字元和div給使用者肉眼看到的游標前的字元是不一樣的,這樣就會出現偏差,刪除的和使用者認為刪除的不是同一個

那麼本著先修改掉此類問題的想法,開始了又一次探索

首先因為需求又增加了換行要求,所以我將輸入框(input)換成了textarea,其次我沒有使用angular進行兩個資料的繫結和監聽,我使用了繫結input事件對輸入框進行監聽,每次獲得輸入框中的值,這樣當輸入中文時同樣會獲得值顯示在div上,其他設定都是為了讓textarea和div儘量保持一致。

對於關鍵字的高亮,實現原理就是通過正則表示式把所有的匹配原則先通過正則表示出來,之後利用replace()方法進行替換

replace()方法傳遞的兩個引數,第一個引數是正則,第二個引數同樣可以是個函式,函式內的引數同樣可以幫助我們去進行一些比較複雜的替換機制