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 相关文章推荐
jQuery基本过滤选择器使用介绍
Apr 18 Javascript
node.js中的path.isAbsolute方法使用说明
Dec 08 Javascript
JavaScript中的Math.LOG2E属性使用详解
Jun 14 Javascript
javascript实现倒计时(精确到秒)
Jun 26 Javascript
cocos2dx骨骼动画Armature源码剖析(三)
Sep 08 Javascript
原生js实现tab选项卡切换
Mar 23 Javascript
Bootstrap栅格系统学习笔记
Nov 25 Javascript
JS双击变input框批量修改内容
Dec 12 Javascript
在vue项目中优雅的使用SVG的方法实例详解
Dec 03 Javascript
一次让你了解全部JavaScript的作用域
Jun 24 Javascript
使用webpack/gulp构建TypeScript项目的方法示例
Dec 18 Javascript
浅谈JavaScript中this的指向更改
Jul 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脚本的10个技巧(4)
2006/10/09 PHP
用php来改写404错误页让你的页面更友好
2013/01/24 PHP
thinkphp实现上一篇与下一篇的方法
2014/12/08 PHP
汇总PHPmailer群发Gmail的常见问题
2016/02/24 PHP
php+ajax实现带进度条的上传图片功能【附demo源码下载】
2016/09/14 PHP
PHP中ajax无刷新上传图片与图片下载功能
2017/02/21 PHP
Jquery 基础学习笔记
2009/05/29 Javascript
js 实现无干扰阴影效果 简单好用(附文件下载)
2009/12/27 Javascript
jQuery+ajax实现顶一下,踩一下效果
2010/07/17 Javascript
JavaScript中的noscript元素属性位置及作用介绍
2013/04/11 Javascript
Jquery实现图片左右自动滚动示例
2013/09/25 Javascript
javascript模拟地球旋转效果代码实例
2013/12/02 Javascript
Javascript核心读书有感之词法结构
2015/02/01 Javascript
自定义百度分享的分享按钮
2015/03/18 Javascript
使用AngularJS创建自定义的过滤器的方法
2015/06/18 Javascript
Javascript模仿淘宝信用评价实例(附源码)
2015/11/26 Javascript
BootStrap的Datepicker控件使用心得分享
2016/05/25 Javascript
Javascript打印局部页面实例
2016/06/21 Javascript
jQuery基本选择器之标签名选择器
2016/09/03 Javascript
JavaScript创建对象的四种常用模式实例分析
2019/01/11 Javascript
详解js创建对象的几种方法及继承
2019/04/12 Javascript
vue图片加载失败时用默认图片替换的方法
2019/08/29 Javascript
JS如何实现动态添加的元素绑定事件
2019/11/12 Javascript
详解python如何调用C/C++底层库与互相传值
2016/08/10 Python
Python中的二维数组实例(list与numpy.array)
2018/04/13 Python
Python中Proxypool库的安装与配置
2018/10/19 Python
django-allauth入门学习和使用详解
2019/07/03 Python
python lambda表达式(匿名函数)写法解析
2019/09/16 Python
详解html5 canvas 微信海报分享(个人爬坑)
2018/01/12 HTML / CSS
Html5调用手机摄像头并实现人脸识别的实现
2018/12/21 HTML / CSS
Ancheer官方户外和运动商店:销售电动自行车
2019/08/07 全球购物
国贸专业大学生职业生涯规划范文
2014/01/10 职场文书
2014年向国旗敬礼活动总结
2014/09/27 职场文书
写给老师的保证书
2015/05/09 职场文书
2016新年问候语大全
2015/11/11 职场文书
ubuntu如何搭建vsftpd服务器
2022/12/24 Servers