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学习笔记之jQuery的事件
Dec 22 Javascript
Jquery上传插件 uploadify v3.1使用说明
Jun 18 Javascript
JavaScript利用闭包实现模块化
Jan 13 Javascript
jquery easyui dataGrid动态改变排序字段名的方法
Mar 02 Javascript
JS动态添加元素及绑定事件造成程序重复执行解决
Dec 07 Javascript
Angular4学习教程之HTML属性绑定的方法
Jan 04 Javascript
小程序清理本地缓存的方法
Aug 17 Javascript
Angular4 Select选择改变事件的方法
Oct 09 Javascript
微信小程序发送短信验证码完整实例
Jan 07 Javascript
js实现类似iphone的网页滑屏解锁功能示例【附源码下载】
Jun 10 Javascript
微信小程序按顺序同步执行的两种方式
Dec 20 Javascript
vue路由切换时取消之前的所有请求操作
Sep 01 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
IE6背景图片不缓存问题解决方案及图片使用策略多个方法小结
2012/05/14 Javascript
使用jQuery重置(reset)表单的方法
2014/05/05 Javascript
jQuery实现布局高宽自适应的简单实例
2016/05/28 Javascript
微信小程序 实现拖拽事件监听实例详解
2016/11/16 Javascript
文本溢出插件jquery.dotdotdot.js使用方法详解
2017/06/22 jQuery
关于Vue背景图打包之后访问路径错误问题的解决
2017/11/03 Javascript
谈谈JS中的!!
2017/12/07 Javascript
vue 2.x 中axios 封装的get 和post方法
2018/02/28 Javascript
JavaScript中call和apply方法的区别实例分析
2018/08/03 Javascript
Vue 莹石摄像头直播视频实例代码
2018/08/31 Javascript
详解nodejs解压版安装和配置(带有搭建前端项目脚手架)
2018/12/06 NodeJs
JS实现换肤功能的方法实例详解
2019/01/30 Javascript
javascript面向对象程序设计实践常用知识点总结
2019/07/29 Javascript
ElementUI之Message功能拓展详解
2019/10/18 Javascript
Vue常用的全选/反选的示例代码
2020/02/19 Javascript
[37:37]DAC2018 4.4 淘汰赛 Optic vs Mineski 第二场
2018/04/05 DOTA
Python连接mysql数据库的正确姿势
2016/02/03 Python
Python代码解决RenderView窗口not found问题
2016/08/28 Python
Python绘制3D图形
2018/05/03 Python
Python button选取本地图片并显示的实例
2019/06/13 Python
Python基础之函数基本用法与进阶详解
2020/01/02 Python
python如何实现复制目录到指定目录
2020/02/13 Python
Python数据结构dict常用操作代码实例
2020/03/12 Python
python 读取.nii格式图像实例
2020/07/01 Python
如何用python实现一个HTTP连接池
2021/01/14 Python
校园餐饮创业计划书
2014/01/10 职场文书
一岗双责责任书
2014/04/15 职场文书
十佳文明家庭事迹
2014/05/25 职场文书
健康教育评估方案
2014/05/25 职场文书
创先争优活动承诺书
2014/08/30 职场文书
食品委托检验协议书范本
2014/09/12 职场文书
打架赔偿协议书范本
2014/10/26 职场文书
2014年党风廉政工作总结
2014/12/03 职场文书
2014年教研室工作总结
2014/12/06 职场文书
党员反腐倡廉学习心得体会
2015/08/15 职场文书
Python进度条的使用
2021/05/17 Python