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实现id模糊查询的小例子
Mar 19 Javascript
javascript预加载图片、css、js的方法示例介绍
Oct 14 Javascript
js中生成map对象的方法
Jan 09 Javascript
javascript实现数字验证码的简单实例
Feb 10 Javascript
浅谈javascript获取元素transform参数
Jul 24 Javascript
AngularJS Module方法详解
Dec 08 Javascript
正则表达式替换html元素属性的方法
Nov 26 Javascript
JS操作xml对象转换为Json对象示例
Mar 25 Javascript
requirejs + vue 项目搭建详解
Jun 16 Javascript
vue2.0 循环遍历加载不同图片的方法
Mar 06 Javascript
vue.js实现点击后动态添加class及删除同级class的实现代码
Apr 04 Javascript
jQuery动态生成的元素绑定事件操作实例分析
May 04 jQuery
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
使用Sphinx对索引进行搜索
2013/06/25 PHP
[原创]PHP实现生成vcf vcard文件功能类定义与使用方法详解【附demo源码下载】
2017/09/02 PHP
分享一个asp.net pager分页控件
2012/01/04 Javascript
让复选框只能选择一项的方法
2013/10/08 Javascript
使用正则表达式的格式化与高亮显示json字符串
2014/12/03 Javascript
JQuery插件jcarousellite的参数中文说明
2015/05/11 Javascript
javascript通过获取html标签属性class实现多选项卡的方法
2015/07/27 Javascript
JavaScript模拟push
2016/03/06 Javascript
angularjs数组判断是否含有某个元素的实例
2018/02/27 Javascript
微信小程序调用微信支付接口的实现方法
2019/04/29 Javascript
js/jQuery实现全选效果
2019/06/17 jQuery
js JSON.stringify()基础详解
2019/06/19 Javascript
JS实现基本的网页计算器功能示例
2020/01/16 Javascript
JavaScript实现滑动门效果
2020/01/18 Javascript
BootStrap前端框架使用方法详解
2020/02/26 Javascript
在vue中通过render函数给子组件设置ref操作
2020/11/17 Vue.js
[00:47]DOTA2荣耀之路6:天火,天火!
2018/05/30 DOTA
[01:36]极致酷炫!TI9典藏宝瓶+撼地者至宝展示
2019/06/11 DOTA
Python去掉字符串中空格的方法
2014/03/11 Python
用Pycharm实现鼠标滚轮控制字体大小的方法
2019/01/15 Python
python 实现将Numpy数组保存为图像
2020/01/09 Python
Tensorflow: 从checkpoint文件中读取tensor方式
2020/02/10 Python
pycharm 关掉syntax检查操作
2020/06/09 Python
详解html2canvas截图不能截取圆角图片的解决方案
2018/01/30 HTML / CSS
馥绿德雅美国官方网站:Rene Furterer头皮护理专家
2019/05/01 全球购物
女大学生毕业找工作的自我评价
2013/10/03 职场文书
留学经费担保书
2014/05/12 职场文书
明星邀请函
2015/02/02 职场文书
实习护士自荐信
2015/03/25 职场文书
烈士陵园观后感
2015/06/08 职场文书
物业公司管理制度
2015/08/05 职场文书
2016年11月份红领巾广播稿
2015/12/21 职场文书
青年岗位能手事迹材料(2016推荐版)
2016/03/01 职场文书
Python实现打乒乓小游戏
2021/09/25 Python
SpringCloud Function SpEL注入漏洞分析及环境搭建
2022/04/08 Java/Android
Java工作中实用的代码优化技巧分享
2022/04/21 Java/Android