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 相关文章推荐
js自动生成对象的属性示例代码
Oct 28 Javascript
JS案例分享之金额小写转大写
May 15 Javascript
jQuery中DOM树操作之复制元素的方法
Jan 23 Javascript
javascript中的previousSibling和nextSibling的正确用法
Sep 16 Javascript
Bootstrap table的使用方法
Nov 02 Javascript
通过扫描二维码打开app的实现代码
Nov 10 Javascript
js学习之----深入理解闭包
Nov 21 Javascript
详解js中call与apply关键字的作用
Nov 21 Javascript
Vue.js 插件开发详解
Mar 29 Javascript
Koa2 之文件上传下载的示例代码
Mar 29 Javascript
微信小程序项目实践之验证码倒计时功能
Jul 18 Javascript
java和js实现的洗牌小程序
Sep 30 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文件下载实例代码浅析
2016/08/17 PHP
PHP的JSON封装、转变及输出操作示例
2019/09/27 PHP
js 动态选中下拉框
2009/11/26 Javascript
jquery判断字符输入个数(数字英文长度记为1,中文记为2,超过长度自动截取)
2010/10/15 Javascript
让浏览器非阻塞加载javascript的几种方法小结
2011/04/25 Javascript
基于jquery实现后台左侧菜单点击上下滑动显示
2013/04/11 Javascript
vue一步步实现alert功能
2017/07/05 Javascript
JavaScript寄生组合式继承原理与用法分析
2019/01/11 Javascript
uni-app微信小程序登录并使用vuex存储登录状态的思路详解
2019/11/04 Javascript
基于element-ui对话框el-dialog初始化的校验问题解决
2020/09/11 Javascript
在Python的Django框架上部署ORM库的教程
2015/04/20 Python
使用url_helper简化Python中Django框架的url配置教程
2015/05/30 Python
python3.5使用tkinter制作记事本
2016/06/20 Python
Python实现读取TXT文件数据并存进内置数据库SQLite3的方法
2017/08/08 Python
对numpy中向量式三目运算符详解
2018/10/31 Python
python 用opencv调用训练好的模型进行识别的方法
2018/12/07 Python
Django组件之cookie与session的使用方法
2019/01/10 Python
python实现列表的排序方法分享
2019/07/01 Python
python实现控制电脑鼠标和键盘,登录QQ的方法示例
2019/07/06 Python
Python 图像对比度增强的几种方法(小结)
2019/09/25 Python
python实现机器人卡牌
2019/10/06 Python
基于python plotly交互式图表大全
2019/12/07 Python
Python 使用 environs 库定义环境变量的方法
2020/02/25 Python
Django model.py表单设置默认值允许为空的操作
2020/05/19 Python
pip 20.3 新版本发布!即将抛弃 Python 2.x(推荐)
2020/12/16 Python
python基于openpyxl生成excel文件
2020/12/23 Python
animation和transition的区别
2020/10/12 HTML / CSS
使用HTML5 Canvas API控制字体的显示与渲染的方法
2016/03/24 HTML / CSS
澳大利亚运动鞋商店:Platypus Shoes
2019/09/27 全球购物
贝佳斯官方网站:Borghese
2020/05/08 全球购物
化学教学随笔感言
2014/02/19 职场文书
蛋糕店创业计划书范文
2014/09/21 职场文书
公务员党的群众路线教育实践活动学习心得体会
2014/10/30 职场文书
2015年父亲节寄语
2015/03/23 职场文书
高校自主招生教师推荐信
2015/03/23 职场文书
勤俭节约倡议书范文
2015/04/29 职场文书