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 &amp;&amp;和||运算法的另类使用技巧
Nov 28 Javascript
JQuery扩展插件Validate 5添加自定义验证方法
Sep 05 Javascript
5个数组Array方法: indexOf、filter、forEach、map、reduce使用实例
Jan 29 Javascript
修复jQuery tablesorter无法正确排序的bug(加千分位数字后)
Mar 30 Javascript
JavaScript创建对象的七种方式(推荐)
Jun 26 Javascript
浅谈vue的iview列表table render函数设置DOM属性值的方法
Sep 30 Javascript
解决Angular4项目部署到服务器上刷新404的问题
Aug 31 Javascript
浅谈Angular 观察者模式理解
Nov 01 Javascript
用vuex写了一个购物车H5页面的示例代码
Dec 04 Javascript
layui 点击重置按钮, select 并没有被重置的解决方法
Sep 03 Javascript
JS array数组检测方式解析
May 19 Javascript
详解微信小程序(Taro)手动埋点和自动埋点的实现
Mar 02 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不用正则采集速度探究总结
2008/03/24 PHP
详解PHP+AJAX无刷新分页实现方法
2015/11/03 PHP
PHP的PDO预定义常量讲解
2019/01/24 PHP
thinkPHP5.1框架中Request类四种调用方式示例
2019/08/03 PHP
jquery validate在ie8下的bug解决方法
2013/11/13 Javascript
javascript阻止浏览器后退事件防止误操作清空表单
2013/11/22 Javascript
jquery实现更改表格行顺序示例
2014/04/30 Javascript
原生javascript实现拖动元素示例代码
2014/09/01 Javascript
在JS中操作时间之getUTCMilliseconds()方法的使用
2015/06/10 Javascript
整理AngularJS中的一些常用指令
2015/06/16 Javascript
动态加载jQuery的两种方法实例分析
2015/07/17 Javascript
基于Css3和JQuery实现打字机效果
2015/08/11 Javascript
JS 通过系统时间限定动态添加 select option的实例代码
2016/06/09 Javascript
angularjs封装$http为factory的方法
2017/05/18 Javascript
JavaScript实现时间表动态效果
2017/07/15 Javascript
基于vue实现可搜索下拉框定制组件
2020/03/26 Javascript
详解微信JS-SDK选择图片遇到的坑
2018/08/15 Javascript
javascript 代码是如何被压缩的示例代码
2020/05/06 Javascript
JavaScript实现烟花绽放动画效果
2020/08/04 Javascript
详解vue中v-model和v-bind绑定数据的异同
2020/08/10 Javascript
在VUE中使用lodash的debounce和throttle操作
2020/11/09 Javascript
vue绑定class的三种方法
2020/12/24 Vue.js
[02:33]2018DOTA2亚洲邀请赛赛前采访——LGD
2018/04/04 DOTA
wxPython中listbox用法实例详解
2015/06/01 Python
Python逐行读取文件中内容的简单方法
2019/02/26 Python
Pycharm如何打断点的方法步骤
2019/06/13 Python
如何使用python进行pdf文件分割
2019/11/11 Python
如何验证python安装成功
2020/07/06 Python
Django DRF认证组件流程实现原理详解
2020/08/17 Python
DC Shoes官网:美国滑板鞋和服饰品牌
2017/09/03 全球购物
最新大学职业规划书范文
2013/12/30 职场文书
结婚保证书范文
2014/04/29 职场文书
幼儿园中班个人总结
2015/02/28 职场文书
纪录片信仰观后感
2015/06/08 职场文书
2019安全宣传标语大全
2019/08/14 职场文书
Java 关于String字符串原理上的问题
2022/04/07 Java/Android