js实现@提到好友

转载请注明: TheViper http://www.cnblogs.com/TheViper

要求

1.输入@时,弹出匹配的好友菜单

2.光标进入包含有"@好友"的标签时,弹出菜单

3.按backspace删除时,如果光标前面是包含有"@好友"的标签,弹出菜单

4.兼容ie,firefox.

具体做法

针对要求一,很自然的会想到对输入框绑定事件。这里要绑定mousedown,而不是mouseup.因为如果是mouseup的话,用event.preventDefault()是无法阻止键盘输入@的。另外,这里在事件回调中用return false也是起不了作用的。

绑定mousedown事件后,就要插入自定义的包含有"@好友"的标签了。新浪微博的输入框是用textarea做的,无法知道其内部是怎样处理的,只好看百度贴吧了。

可以看到,贴吧是插入了<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("&nbsp;<span id=‘at"+at_index+"‘ class=‘at_span‘>@</span>&nbsp;");
                }else{
                    document.execCommand("insertHtml", false,"&nbsp;<span id=‘at"+at_index+"‘ class=‘at_span‘>@</span>&nbsp;");
                }
                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("&nbsp;<span id=‘at"+at_index+"‘ class=‘at_span‘>@</span>&nbsp;");
                }else{
                    document.execCommand("insertHtml", false,"&nbsp;<span id=‘at"+at_index+"‘ class=‘at_span‘>@</span>&nbsp;");
                }
                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++。

上面是监听[email protected],接着是监听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

ie8

ie7

ie6

例子下载

时间: 2024-10-19 03:09:36

js实现@提到好友的相关文章

另一种场景下的js @提到好友

转载请注明: TheViper http://www.cnblogs.com/TheViper  在输入框中@好友这个功能很常见,具体效果大概有两种: 1.像js实现@提到好友,在输入框中输入@时,根据@后面的字符,弹出相应好友菜单. 2.增加一个按钮,点击后出现包含所有好友的弹出层. 本文就介绍本屌在实现第二种@时走过的一些坑.为了简单,其中的什么弹出层,拉数据就不说了. 先说下要求: 1.添加@好友时,无论编辑器有没有焦点,@好友都会被添加到上一个焦点位置,效果和更简单的 编辑器从光标处插入

如何通过js给QQ好友发送信息

一般我们在做页面活动的时候可能会碰到点击一个按钮把一些相关的信息通过QQ发送给你的好友,这种信息推送的功能该如何实现呢!下面我来介绍下使用方法! 代码如下: <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8"/> <title>xxx</title> </head> <body> <a h

js基础知识点收集

js基础知识点收集 js常用基本类型 function show(x) { console.log(typeof(x)); // undefined console.log(typeof(10)); // number console.log(typeof('abc')); // string console.log(typeof(true)); // boolean console.log(typeof([])); // object console.log(typeof(function (

sea.js 个人入门

头顶 美工.切图仔 头衔的我 出去面试时面试官必问的一题: 用过 seajs.requirejs 么? 答案当然是否定的,然后面试官就是鲁迅先生的前半句诗"横眉冷对千夫指 "看我. 所以就看看看了看API 玉伯 : http://weibo.com/lifesinger?noscale_head=1#_0 说这两个JS 必须提到AMD.commonjs两种不同的规范: 奇舞团:http://www.75team.com/archives/882 知乎:http://www.zhihu.

CSS vs JS动画:谁更快?

CSS vs JS动画:谁更快? 2016-05-16 前端大全 (点击上方公众号,可快速关注) 英文:Julian Shapiro 译者:MZhou's blog 链接:http://zencode.in/19.CSS-vs-JS动画:谁更快?.html 这篇文章翻译自 Julian Shapiro 的 CSS vs. JS Animation: Which is Faster?.Julian Shapiro 也是 Velocity.js 的创造者.这是一个非常高效.简单易用的JS动画库.他在

0003.深入理解JavaScript系列学习:编写高质量JavaScript代码的基本要点

推荐 汤姆大叔博客园深入理解JavaScript系列 此文来源:http://www.cnblogs.com/TomXu/archive/2011/12/28/2286877.html 书写可维护的代码(Writing Maintainable Code ) 即 代码的可读写维护性 博客园<行者自若的技术笔记> 中参考代码规范与读写可维护性 可作为参考,我也转载了文章到自己的博客园 http://www.cnblogs.com/wolongjv/articles/5937898.html 概括

Meteor入门介绍

Meteor是什么 基于nodejs的实时web APP开发框架. Meteor能带来什么 简单的说,你可以用js搞定客户端.服务端的开发.另外,客户端.服务端的界限被极大的模糊.客户端的界面跟服务端的数据是双向绑定的,修改服务端的数据,用户界面会随着更新:你也可以在客户端直接修改服务端的数据库. 系统的归纳下,对于(前端)开发者来说,可能比较吸引人的点. 统一开发语言:客户端.服务端都可以用js搞定. 提高开发效率:开发者可以用10行左右的代码就开发出一个具有多点实时更新的应用,因为底层框架已

dojo 加载Json数据

1.今天研究了dojo datagrid加载WebService后台传上来的数据.研究来研究去发现他不是很难.用谷歌多调试一下就好了. 2.看很多例子,这个例子能够更好的帮我解决问题:https://dojotoolkit.org/documentation/tutorials/1.10/dojo_data/index.html 往下滑动页面会看到类似于下面例子的截图: 3.框架都好说,把字段对应上问题不大,主要是数据.我开始是直接将WebService传出来的JSON数据传入给Memory的d

详解JavaScript中的原型和继承-转自颜海镜大大

本文将会介绍面向对象,继承,原型等相关知识,涉及的知识点如下: 面向对象与继承 CEOC OLOO 臃肿的对象 原型与原型链 修改原型的方式 面向对象与继承 最近学习了下python,还写了篇博文<重拾编程乐趣——我的Python笔记>,加深了我对面向对象的一些理解. 我们会对我们写的程序进行抽象,而不同的语言都提供了不同的抽象工具,比如各种语言里面的数组,集合(键值数组,哈希表,字典等)等提供了对数据的抽象:而VB里面的子程序,类C语言里面的函数,提供了抽象代码段的能力. 有时我们希望将数据