項(xiàng)目中要求實(shí)現(xiàn)一個(gè)功能,在輸入框中輸入特定的搜索語句,當(dāng)輸入為關(guān)鍵字時(shí),關(guān)鍵字高亮,且輸入滿一行進(jìn)行換行操作
首先分析如果想實(shí)現(xiàn)一部分關(guān)鍵字高亮,輸入框本身肯定是做不到的,因?yàn)閷?shí)現(xiàn)高亮需要通過動態(tài)的給關(guān)鍵字添加span標(biāo)簽,再給span標(biāo)簽中的內(nèi)容設(shè)置顏色
如果使用div,那必須給div添加contenteditable = "true"屬性,使其div可輸入,其次監(jiān)聽按鍵是否抬起,對div中的內(nèi)容進(jìn)行檢測并替換關(guān)鍵字,我在嘗試這種方法時(shí)遇到了幾個(gè)問題,第一個(gè)問題是每次輸入內(nèi)容進(jìn)行替換后光標(biāo)自動定位在開頭,此問題在網(wǎng)上查找資料解決如下
function po_Last_Div(obj) {
? ? if (window.getSelection) {//ie11 10 9 ff safari
? ? ? ? obj.focus(); //解決ff不獲取焦點(diǎn)無法定位問題
? ? ? ? var range = window.getSelection();//創(chuàng)建range
? ? ? ? range.selectAllChildren(obj);//range 選擇obj下所有子內(nèi)容
? ? ? ? range.collapseToEnd();//光標(biāo)移至最后
? ? }
else if (document.selection) {//ie10 9 8 7 6 5
? ? ? ? var range = document.selection.createRange();//創(chuàng)建選擇對象
? ? ? ? //var range = document.body.createTextRange();
? ? ? ? range.moveToElementText(obj);//range定位到obj
? ? ? ? range.collapse(false);//光標(biāo)移至最后
? ? ? ? range.select();
? ? }
}
第二個(gè)問題為如果用戶將關(guān)鍵字改變,但程序進(jìn)行監(jiān)聽時(shí)獲取的還是加了span標(biāo)簽的內(nèi)容,所以當(dāng)關(guān)鍵字被修改成不是關(guān)鍵字時(shí),其高亮并沒有消失,此問題的解決辦法就是每次監(jiān)聽到有鍵按下,獲取div的文本值(div.text()),然后使用replace()方法將獲取到的文本值中的空格替換成 (這塊的替換因?yàn)樵诓檎谊P(guān)鍵字時(shí)要利用正則表達(dá)式,正則表達(dá)式中有 ),再根據(jù)需求中對關(guān)鍵字的定義進(jìn)行各種匹配與替換。在顯示的時(shí)候用html()方法讓瀏覽器對一些標(biāo)簽進(jìn)行轉(zhuǎn)化
第三個(gè)問題是當(dāng)輸入中文時(shí)在虛擬按鍵中,應(yīng)用程序同樣監(jiān)聽按鍵,所以中文輸入時(shí)會出現(xiàn)來回跳轉(zhuǎn),并把中文輸入未結(jié)束的拼音同樣顯示在頁面上,此問題的原因主要是因?yàn)槲彝ㄟ^監(jiān)聽按鍵來判斷內(nèi)容修改,至此未找到能很好解決此問題的方法,畢竟還是前端小白一枚。
這條路走死后,我又回到原項(xiàng)目中,研究其實(shí)現(xiàn)原理,和該原理出現(xiàn)的bug
原項(xiàng)目中實(shí)現(xiàn)的原理,大邏輯是使用angularjs將一個(gè)輸入框和div綁定,輸入框使用ng-bind將值傳遞給應(yīng)用程序控制器,之后對輸入框的值進(jìn)行處理(關(guān)鍵字實(shí)現(xiàn)高亮),然后將div添加ng-bind-html屬性(用于顯示關(guān)鍵字高亮的內(nèi)容),最后將改變后的內(nèi)容顯示在界面
在這過程中,讓輸入框中的內(nèi)容透明,在輸入框中的上層有div,用戶看到的是div顯示出來的帶有高亮的內(nèi)容,但是實(shí)際操作的是下面被設(shè)置為透明顏色的輸入框
在此方法的實(shí)現(xiàn)過程中,會出現(xiàn)三個(gè)bug
第一、當(dāng)輸入中文時(shí),虛擬輸入內(nèi)容不顯示,看不到輸入的拼英,只有字,分析出現(xiàn)此問題的原因是因?yàn)檩斎肟蚝蚫iv進(jìn)行綁定是值的綁定,所以當(dāng)輸入中文時(shí),只有我們的值才會被傳遞,拼英不會顯示
第二、因?yàn)檩斎肟虻淖煮w間隔和div中顯示的字體間隔不一樣,當(dāng)輸入過多內(nèi)容的時(shí)候,輸入框的光標(biāo)會和div輸入的值重疊(雖然輸入框的內(nèi)容設(shè)置為透明,但光標(biāo)還可以看見,所以div是沒有光標(biāo)的,是用input光標(biāo),div的內(nèi)容)
第三、當(dāng)用戶在輸入一段值后又想在中間插入值時(shí),這時(shí)又出現(xiàn)了問題,input輸入框的光標(biāo)會動來動去,這時(shí)input框中光標(biāo)位置的字符和div給用戶肉眼看到的光標(biāo)前的字符是不一樣的,這樣就會出現(xiàn)偏差,刪除的和用戶認(rèn)為刪除的不是同一個(gè)
那么本著先修改掉此類問題的想法,開始了又一次探索
首先因?yàn)樾枨笥衷黾恿藫Q行要求,所以我將輸入框(input)換成了textarea,其次我沒有使用angular進(jìn)行兩個(gè)數(shù)據(jù)的綁定和監(jiān)聽,我使用了綁定input事件對輸入框進(jìn)行監(jiān)聽,每次獲得輸入框中的值,這樣當(dāng)輸入中文時(shí)同樣會獲得值顯示在div上,其他設(shè)置都是為了讓textarea和div盡量保持一致。
對于關(guān)鍵字的高亮,實(shí)現(xiàn)原理就是通過正則表達(dá)式把所有的匹配原則先通過正則表示出來,之后利用replace()方法進(jìn)行替換
replace()方法傳遞的兩個(gè)參數(shù),第一個(gè)參數(shù)是正則,第二個(gè)參數(shù)同樣可以是個(gè)函數(shù),函數(shù)內(nèi)的參數(shù)同樣可以幫助我們?nèi)ミM(jìn)行一些比較復(fù)雜的替換機(jī)制