js完美实现@提到好友特效(兼容各大浏览器)


Posted in Javascript onMarch 16, 2015

要求

1.输入@时,弹出匹配的好友菜单

2.光标进入包含有"@好友"的标签时,弹出菜单

3.按backspace删除时,如果光标前面是包含有"@好友"的标签,弹出菜单

4.兼容ie,firefox.

具体做法

针对要求一,很自然的会想到对输入框绑定事件。这里要绑定mousedown,而不是mouseup.因为如果是mouseup的话,用event.preventDefault()是无法阻止键盘输入@的。另外,这里在事件回调中用return false也是起不了作用的。

绑定mousedown事件后,就要插入自定义的包含有"@好友"的标签了。新浪微博的输入框是用textarea做的,无法知道其内部是怎样处理的,只好看百度贴吧了。

js完美实现@提到好友特效(兼容各大浏览器)

可以看到,贴吧是插入了<span class='at'></span>标签。这应该是方便后台用正则表达式匹配。

具体的

        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();

            }

        };

这里需要在光标处插入,所以用到了range.

然后就是菜单显示了,关键在于怎么定位。我的做法很垃圾,就是为插入的span添加id,然后根据span id的位置为菜单定位。如果有更好的做法,请告诉我一声。

具体的

    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根据新插入的span id,为at_box定位,然后显示菜单。cur_index表示光标当前所在的span id.设置这个变量因为用户可能倒回去改已经插入的span,而at_index是一直递增的,所以这里就还需要一个变量。

用户点击菜单中好友项,触发item_click回调。回调里就是将好友名字用innserHTML添加到当前span里面.然后隐藏菜单,at_index++。

上面是监听shift+@,接着是监听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的作用是获取光标前的内容.由于兼容性,这个函数在标准浏览器中可以得到是光标前所有内容的DocumentFragment,而在ie中就只能得到文本(不是node)了,不过这个html字符串可以转换成DocumentFragment.在avalon中用parseHTML就可以将html字符串变成node了。jquery中用$(html)[0]也能得到node.

有了这个函数,再用lastChild就可以判断光标是不是在光标前html的lastChild里,并且这个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';

            }

最后是光标进入span标签,显示菜单。这个很显然需要绑定鼠标事件。这里绑定mouseup,因为如果绑定mousedown的话,需要鼠标在span标签再点一次才能显示菜单。至于原理,和上面差不多。

        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';

        };

注意,如果光标在span里面,就要取出它的id,at_box根据这个id定位,另外还要重置cur_index.

至于ajax更新菜单,字符匹配我就不做了

效果

firefox

js完美实现@提到好友特效(兼容各大浏览器)

ie8

js完美实现@提到好友特效(兼容各大浏览器)

ie7

js完美实现@提到好友特效(兼容各大浏览器)

ie6

js完美实现@提到好友特效(兼容各大浏览器)

下载

以上就是本文所述的全部内容了,希望对大家了解javascript能够有所帮助。

Javascript 相关文章推荐
弹出层之1:JQuery.Boxy (一) 使用介绍
Oct 06 Javascript
深入理解JavaScript系列(10) JavaScript核心(晋级高手必读篇)
Jan 15 Javascript
jQuery之ajax删除详解
Feb 27 Javascript
JS访问SWF的函数用法实例
Jul 01 Javascript
原生JS实现N级菜单的代码
May 21 Javascript
vue.js如何更改默认端口号8080为指定端口的方法
Jul 14 Javascript
jQuery实现input输入框获取焦点与失去焦点时提示的消失与显示功能示例
May 27 jQuery
React 全自动数据表格组件——BodeGrid的实现思路
Jun 12 Javascript
浅谈vue权限管理实现及流程
Apr 23 Javascript
深入webpack打包原理及loader和plugin的实现
May 06 Javascript
Vue proxyTable配置多个接口地址,解决跨域的问题
Sep 11 Javascript
解决ant design vue 表格a-table二次封装,slots渲染的问题
Oct 28 Javascript
JavaScript DSL 流畅接口(使用链式调用)实例
Mar 15 #Javascript
JavaScript中的DSL元编程介绍
Mar 15 #Javascript
JavaScript中的立即执行函数表达式介绍
Mar 15 #Javascript
Javascript中的arguments与重载介绍
Mar 15 #Javascript
JavaScript中的闭包介绍
Mar 15 #Javascript
Javascript中的匿名函数与封装介绍
Mar 15 #Javascript
Javascript中的方法链(Method Chaining)介绍
Mar 15 #Javascript
You might like
详解php反序列化
2020/06/10 PHP
xml和web特殊字符
2009/04/28 Javascript
没有document.getElementByName方法
2013/08/19 Javascript
DOM 事件流详解
2015/01/20 Javascript
基于jQuery实现多层次的手风琴效果附源码
2015/09/21 Javascript
JavaScript隐式类型转换
2016/03/15 Javascript
Javascript json object 与string 相互转换的简单实现
2016/09/27 Javascript
js实现九宫格的随机颜色跳转
2017/02/19 Javascript
利用JQuery操作iframe父页面、子页面的元素和方法汇总
2017/09/10 jQuery
微信小程序swiper实现滑动放大缩小效果
2018/11/15 Javascript
JSON字符串操作移除空串更改key/value的介绍
2019/01/05 Javascript
vue+element加入签名效果(移动端可用)
2019/06/17 Javascript
element中table高度自适应的实现
2020/10/21 Javascript
微信小程序调用后台service教程详解
2020/11/06 Javascript
[02:10]DOTA2 TI10勇士令状玩法及不朽Ⅰ展示:焕新世界,如你所期
2020/05/29 DOTA
python中使用百度音乐搜索的api下载指定歌曲的lrc歌词
2014/07/18 Python
python中from module import * 的一个坑
2014/07/20 Python
Python使用urllib模块的urlopen超时问题解决方法
2014/11/08 Python
名片管理系统python版
2018/01/11 Python
Python cookbook(数据结构与算法)保存最后N个元素的方法
2018/02/13 Python
Django使用HttpResponse返回图片并显示的方法
2018/05/22 Python
对numpy中二进制格式的数据存储与读取方法详解
2018/11/01 Python
Python传递参数的多种方式(小结)
2019/09/18 Python
jupyter notebook 多行输出实例
2020/04/09 Python
Python爬取微信小程序Charles实现过程图解
2020/09/29 Python
PHP面试题及答案二
2015/05/23 面试题
专科毕业生求职简历的自我评价
2013/10/12 职场文书
幼儿园义卖活动方案
2014/01/17 职场文书
高中教师评语大全
2014/04/25 职场文书
关于读书的演讲稿300字
2014/08/27 职场文书
党员先进性教育整改措施
2014/09/18 职场文书
村党建工作汇报材料
2014/11/02 职场文书
小学科学课教学反思
2016/02/23 职场文书
golang http使用踩过的坑与填坑指南
2021/04/27 Golang
Eclipse+Java+Swing+Mysql实现电影购票系统(详细代码)
2022/01/18 Java/Android
排查Tomcat进程假死的问题
2022/05/06 Servers