js完美實(shí)現(xiàn)@提到好友特效(兼容各大瀏覽器)
要求
1.輸入@時(shí),彈出匹配的好友菜單
2.光標(biāo)進(jìn)入包含有"@好友"的標(biāo)簽時(shí),彈出菜單
3.按backspace刪除時(shí),如果光標(biāo)前面是包含有"@好友"的標(biāo)簽,彈出菜單
4.兼容ie,firefox.
具體做法
針對(duì)要求一,很自然的會(huì)想到對(duì)輸入框綁定事件。這里要綁定mousedown,而不是mouseup.因?yàn)槿绻莔ouseup的話,用event.preventDefault()是無(wú)法阻止鍵盤輸入@的。另外,這里在事件回調(diào)中用return false也是起不了作用的。
綁定mousedown事件后,就要插入自定義的包含有"@好友"的標(biāo)簽了。新浪微博的輸入框是用textarea做的,無(wú)法知道其內(nèi)部是怎樣處理的,只好看百度貼吧了。

可以看到,貼吧是插入了<span class='at'></span>標(biāo)簽。這應(yīng)該是方便后臺(tái)用正則表達(dá)式匹配。
具體的
vm.check_key=function(e){
var editor=$('editor'),range;
if(e.shiftKey&&e.keyCode==50){
if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.pasteHTML(" <span id='at"+at_index+"' class='at_span'>@</span> ");
}else{
document.execCommand("insertHtml", false," <span id='at"+at_index+"' class='at_span'>@</span> ");
}
e.preventDefault();
}
};
這里需要在光標(biāo)處插入,所以用到了range.
然后就是菜單顯示了,關(guān)鍵在于怎么定位。我的做法很垃圾,就是為插入的span添加id,然后根據(jù)span id的位置為菜單定位。如果有更好的做法,請(qǐng)告訴我一聲。
具體的
function at_box_show(at){
var at_pos=avalon($(at)).position();
$('at_box').style.left=at_pos.left+'px';
$('at_box').style.top=at_pos.top+16+'px';
$('at_box').style.display='block';
}
var at_index=0,cur_index=0;
avalon.define('editor', function(vm) {
vm.item_click=function(){
$('at'+cur_index).innerHTML="@"+this.innerHTML;
$('at_box').style.display='none';
at_index++;
};
vm.check_key=function(e){
var editor=$('editor'),a=getCharacterPrecedingCaret(editor),range;
if(e.shiftKey&&e.keyCode==50){
if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.pasteHTML(" <span id='at"+at_index+"' class='at_span'>@</span> ");
}else{
document.execCommand("insertHtml", false," <span id='at"+at_index+"' class='at_span'>@</span> ");
}
at_box_show('at'+at_index);
cur_index=at_index;
e.preventDefault();
}
};
});
at_show_box根據(jù)新插入的span id,為at_box定位,然后顯示菜單。cur_index表示光標(biāo)當(dāng)前所在的span id.設(shè)置這個(gè)變量因?yàn)橛脩艨赡艿够厝ジ囊呀?jīng)插入的span,而at_index是一直遞增的,所以這里就還需要一個(gè)變量。
用戶點(diǎn)擊菜單中好友項(xiàng),觸發(fā)item_click回調(diào)?;卣{(diào)里就是將好友名字用innserHTML添加到當(dāng)前span里面.然后隱藏菜單,at_index++。
上面是監(jiān)聽(tīng)shift+@,接著是監(jiān)聽(tīng)backspace刪除。
function getTextBeforeCursor(containerEl) {
var precedingChar = "", sel, range, precedingRange;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount > 0) {
range = sel.getRangeAt(0).cloneRange();
range.collapse(true);
range.setStart(containerEl, 0);
precedingChar = range.cloneContents();
}
} else if ( (sel = document.selection)) {
range = sel.createRange();
precedingRange = range.duplicate();
precedingRange.moveToElementText(containerEl);
precedingRange.setEndPoint("EndToStart", range);
precedingChar = precedingRange.htmlText;
}
return precedingChar;
}
getTextBeforeCursor的作用是獲取光標(biāo)前的內(nèi)容.由于兼容性,這個(gè)函數(shù)在標(biāo)準(zhǔn)瀏覽器中可以得到是光標(biāo)前所有內(nèi)容的DocumentFragment,而在ie中就只能得到文本(不是node)了,不過(guò)這個(gè)html字符串可以轉(zhuǎn)換成DocumentFragment.在avalon中用parseHTML就可以將html字符串變成node了。jquery中用$(html)[0]也能得到node.
有了這個(gè)函數(shù),再用lastChild就可以判斷光標(biāo)是不是在光標(biāo)前html的lastChild里,并且這個(gè)lastChild是span。
具體的
var a=getTextBeforeCursor($('editor'));
if(e.keyCode==8){
if(!-[1,]){
var b=avalon.parseHTML(a).lastChild;
}else{
var b=a.lastChild;
}
if(b.nodeType==1&&b.nodeName=='SPAN'){
var id=b.id;
cur_index=b.id.substring(2);
at_box_show(b.id);
}else
$('at_box').style.display='none';
}
最后是光標(biāo)進(jìn)入span標(biāo)簽,顯示菜單。這個(gè)很顯然需要綁定鼠標(biāo)事件。這里綁定mouseup,因?yàn)槿绻壎╩ousedown的話,需要鼠標(biāo)在span標(biāo)簽再點(diǎn)一次才能顯示菜單。至于原理,和上面差不多。
vm.check_mouse=function(e){
var editor=$('editor'),a=getTextBeforeCursor(editor);
if(!-[1,]){
var b=avalon.parseHTML(getTextBeforeCursor(editor)).lastChild;
}else{
var b=a.lastChild;
}
if(b!=null&&b.nodeType==1&&b.nodeName=='SPAN'){
var id=b.id;
cur_index=b.id.substring(2);
at_box_show(b.id);
}else
$('at_box').style.display='none';
};
注意,如果光標(biāo)在span里面,就要取出它的id,at_box根據(jù)這個(gè)id定位,另外還要重置cur_index.
至于ajax更新菜單,字符匹配我就不做了
效果
firefox

ie8

ie7

ie6

以上就是本文所述的全部?jī)?nèi)容了,希望對(duì)大家了解javascript能夠有所幫助。
- jquery插件orbit.js實(shí)現(xiàn)圖片折疊輪換特效
- jquery插件star-rating.js實(shí)現(xiàn)星級(jí)評(píng)分特效
- 原生js實(shí)現(xiàn)移動(dòng)開發(fā)輪播圖、相冊(cè)滑動(dòng)特效
- 原生js和jquery實(shí)現(xiàn)圖片輪播特效
- 原生js和jQuery寫的網(wǎng)頁(yè)選項(xiàng)卡特效對(duì)比
- avalonjs制作響應(yīng)式瀑布流特效
- 基于jQuery.Hz2Py.js插件實(shí)現(xiàn)的漢字轉(zhuǎn)拼音特效
- jQuery插件bgStretcher.js實(shí)現(xiàn)全屏背景特效
- 原生js與jQuery實(shí)現(xiàn)簡(jiǎn)單的tab切換特效對(duì)比
- JS特效實(shí)現(xiàn)圖片自動(dòng)播放并可控的效果
- JavaScript入門基礎(chǔ)
相關(guān)文章
原生js實(shí)現(xiàn)倒計(jì)時(shí)功能(多種格式調(diào)用)
本文主要介紹了原生js實(shí)現(xiàn)倒計(jì)時(shí)(多種格式調(diào)用)的方法,具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01
js 創(chuàng)建對(duì)象 經(jīng)典模式全面了解
下面小編就為大家?guī)?lái)一篇js 創(chuàng)建對(duì)象 經(jīng)典模式全面了解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
javascript學(xué)習(xí)隨筆(使用window和frame)的技巧
javascript學(xué)習(xí)隨筆(使用window和frame)的技巧...2007-03-03
JavaScript獲取flash對(duì)象與網(wǎng)上的有所不同
關(guān)于js獲取flash對(duì)象,網(wǎng)上有非常多的例子,但不是我想要的,經(jīng)測(cè)試整理,因此本文誕生了2014-04-04
avalon js實(shí)現(xiàn)仿微博拖動(dòng)圖片排序
玩微博的朋友都上傳過(guò)圖像吧,當(dāng)圖片上傳后用戶是可以隨意拖動(dòng)圖片的,調(diào)整圖片的順序,那么此功能是怎么實(shí)現(xiàn)的,下面小編通過(guò)此篇文章給大家詳解基于avalon js實(shí)現(xiàn)仿微博拖動(dòng)圖片排序,需要的朋友可以參考下2015-08-08
js實(shí)現(xiàn)滑動(dòng)到頁(yè)面底部自動(dòng)加載更多功能
本文主要分享了js實(shí)現(xiàn)滑動(dòng)到頁(yè)面底部自動(dòng)加載更多功能的代碼。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02
WebApi+Bootstrap+KnockoutJs打造單頁(yè)面程序
這篇文章主要介紹了WebApi+Bootstrap+KnockoutJs打造單頁(yè)面程序的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05

