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 相关文章推荐
javascript 强制刷新页面的实现代码
Dec 13 Javascript
script标签属性type与language使用选择
Dec 02 Javascript
jQuery - css() 方法示例详解
Jan 16 Javascript
javascript中使用new与不使用实例化对象的区别
Jun 22 Javascript
每天一篇javascript学习小结(Function对象)
Nov 16 Javascript
分享我的jquery实现下拉菜单心的
Nov 29 Javascript
js 定位到某个锚点的方法
Nov 19 Javascript
angular中实现li或者某个元素点击变色的两种方法
Jul 27 Javascript
Node.js如何优雅的封装一个实用函数的npm包的方法
Apr 29 Javascript
Moment.js实现多个同时倒计时
Aug 26 Javascript
JavaScript 反射和属性赋值实例解析
Oct 28 Javascript
vue 监听窗口变化对页面部分元素重新渲染操作
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 register_shutdown_function()函数的使用示例
2015/06/23 PHP
简要剖析PHP的Yii框架的组件化机制的基本知识
2016/03/17 PHP
PHP 获取 ping 时间的实现方法
2017/09/29 PHP
基于jquery实现的移入页面上空文本框时,让它变为焦点,移出清除焦点
2011/07/26 Javascript
JavaScript打开word文档的实现代码(c#)
2012/04/16 Javascript
js的for in循环和java里foreach循环的区别分析
2015/01/28 Javascript
JQuery简单实现锚点链接的平滑滚动
2015/05/03 Javascript
nodejs调用cmd命令实现复制目录
2015/05/04 NodeJs
简介JavaScript中的italics()方法的使用
2015/06/08 Javascript
JavaScript中的splice方法用法详解
2016/07/20 Javascript
Node.js的环境安装配置(使用nvm方式)
2016/10/11 Javascript
ajax前台后台跨域请求处理方式
2018/02/08 Javascript
Nodejs实现爬虫抓取数据实例解析
2018/07/05 NodeJs
js中Object.defineProperty()方法的不详解
2018/07/09 Javascript
JS实现动态添加外部js、css到head标签的方法
2019/06/05 Javascript
layer.open组件获取弹出层页面变量、函数的实例
2019/09/25 Javascript
解决Mint-ui 框架Popup和Datetime Picker组件滚动穿透的问题
2020/11/04 Javascript
python进阶教程之异常处理
2014/08/30 Python
Python中int()函数的用法浅析
2017/10/17 Python
python dict 相同key 合并value的实例
2019/01/21 Python
selenium+python自动化测试之多窗口切换
2019/01/23 Python
Python操作redis实例小结【String、Hash、List、Set等】
2019/05/16 Python
Python学习笔记之字符串和字符串方法实例详解
2019/08/22 Python
Python 静态方法和类方法实例分析
2019/11/21 Python
Python代码生成视频的缩略图的实例讲解
2019/12/22 Python
在django中form的label和verbose name的区别说明
2020/05/20 Python
Java byte数组操纵方式代码实例解析
2020/07/22 Python
Python requests接口测试实现代码
2020/09/08 Python
CSS3 animation ? steps 函数详解
2019/08/30 HTML / CSS
中英双版中文教师求职信
2013/10/27 职场文书
自我评价200字分享
2013/12/17 职场文书
体育比赛口号
2014/06/09 职场文书
中国文明网2015年“向国旗敬礼”活动网上签名寄语
2015/09/24 职场文书
如何使用flask将模型部署为服务
2021/05/13 Python
Python 如何解决稀疏矩阵运算
2021/05/26 Python
MySQL中B树索引和B+树索引的区别详解
2022/03/03 MySQL