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 相关文章推荐
js拖动div 当鼠标移动时整个div也相应的移动
Nov 21 Javascript
Node.js中使用事件发射器模式实现事件绑定详解
Aug 15 Javascript
JS实现一个按钮的方法
Feb 05 Javascript
基于jquery实现简单的分页控件
Mar 17 Javascript
js判断checkbox是否选中个数的方法(超简单)
Aug 19 Javascript
Javascript获取某个月的天数
May 30 Javascript
详解vue 项目白屏解决方案
Oct 31 Javascript
引入外部js脚本加载慢与页面白屏问题的解决
Dec 10 Javascript
微信小程序实现带参数的分享功能(两种方法)
May 17 Javascript
在layui框架中select下拉框监听更改事件的例子
Sep 20 Javascript
layui+jquery支持IE8的表格分页方法
Sep 28 jQuery
微信小程序封装多张图片上传api代码实例
Dec 30 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中遇到BOM、编码导致json_decode函数无法解析问题
2014/07/02 PHP
Zend Framework处理Json数据方法详解
2016/12/09 PHP
利用php获得flv视频长度的实例代码
2017/10/26 PHP
js 解决“options为空或不是对象”
2008/12/22 Javascript
JavaScript 学习笔记一些小技巧
2010/03/28 Javascript
jquery实现点击TreeView文本父节点展开/折叠子节点
2013/01/10 Javascript
浅析用prototype定义自己的方法
2013/11/14 Javascript
javascript中replace( )方法的使用
2015/04/24 Javascript
jQuery实现类似淘宝网图片放大效果的方法
2015/07/08 Javascript
基于jQuery实现Ajax验证用户名是否存在实例
2016/03/30 Javascript
用jquery获取自定义的标签属性的值简单实例
2016/09/17 Javascript
jquery使用EasyUI Tree异步加载JSON数据(生成树)
2017/02/11 Javascript
原生JS实现前端本地文件上传
2018/09/08 Javascript
移动端滑动切换组件封装 vue-swiper-router实例详解
2018/11/25 Javascript
[01:32]dota2拉比克至宝(222)
2018/12/20 DOTA
在Django框架中编写Context处理器的方法
2015/07/20 Python
Python之os操作方法(详解)
2017/06/15 Python
python 寻找优化使成本函数最小的最优解的方法
2017/12/28 Python
python实现百度语音识别api
2018/04/10 Python
浅谈django三种缓存模式的使用及注意点
2018/09/30 Python
在win10和linux上分别安装Python虚拟环境的方法步骤
2019/05/09 Python
Python学习笔记之pandas索引列、过滤、分组、求和功能示例
2019/06/03 Python
Python格式化字符串f-string概览(小结)
2019/06/18 Python
浅谈PyQt5 的帮助文档查找方法,可以查看每个类的方法
2019/06/25 Python
python使用sklearn实现决策树的方法示例
2019/09/12 Python
美体小铺印度官网:The Body Shop印度
2019/10/17 全球购物
戴森比利时官方网站:Dyson BE
2020/10/03 全球购物
初任培训自我鉴定
2013/10/07 职场文书
应届生污水处理求职信
2013/11/06 职场文书
采购求职信
2014/03/17 职场文书
淘宝店策划方案
2014/06/07 职场文书
2014年财务工作总结范文
2014/11/11 职场文书
2014年学生工作总结
2014/11/20 职场文书
结婚保证书(三从四德)
2015/02/26 职场文书
Java中CyclicBarrier和CountDownLatch的用法与区别
2021/08/23 Java/Android
Python Pytorch查询图像的特征从集合或数据库中查找图像
2022/04/09 Python