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 相关文章推荐
二级域名转向类
Nov 09 Javascript
jquery Mobile入门—多页面切换示例学习
Jan 08 Javascript
单击复制文字兼容各浏览器的完美解决方案
Jul 04 Javascript
javascript数组详解
Oct 22 Javascript
JS实现仿苹果底部任务栏菜单效果代码
Aug 28 Javascript
全面接触神奇的Bootstrap导航条实战篇
Aug 01 Javascript
jQuery中ScrollTo用法示例
Sep 04 Javascript
Three.js快速入门教程
Sep 09 Javascript
微信小程序图片宽100%显示并且不变形
Jun 21 Javascript
详解node+express+ejs+bootstrap构建项目
Sep 27 Javascript
详解JavaScript的数据类型以及数据类型的转换
Apr 20 Javascript
详解vue-cli@2.x项目迁移日志
Jun 06 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
动态网站web开发 PHP、ASP还是ASP.NET
2006/10/09 PHP
PHP4引用文件语句的对比
2006/10/09 PHP
如何使用PHP往windows中添加用户
2006/12/06 PHP
php对mongodb的扩展(初出茅庐)
2012/11/11 PHP
php根据日期或时间戳获取星座信息和生肖等信息
2015/10/20 PHP
PDO::query讲解
2019/01/29 PHP
javascript读取xml
2006/11/04 Javascript
jQuery中insertAfter()方法用法实例
2015/01/08 Javascript
Angular实现跨域(搜索框的下拉列表)
2017/02/16 Javascript
jQuery实现简单的滑动导航代码(移动端)
2017/05/22 jQuery
Vue动态组件实例解析
2017/08/20 Javascript
React实践之Tree组件的使用方法
2017/09/30 Javascript
微信小程序实现单选功能
2018/10/30 Javascript
我要点爆”微信小程序云开发之项目建立与我的页面功能实现
2019/05/26 Javascript
微信小程序 函数防抖 解决重复点击消耗性能问题实现代码
2019/09/12 Javascript
判断JavaScript中的两个变量是否相等的操作符
2019/12/21 Javascript
javascript实现搜索筛选功能实例代码
2020/11/12 Javascript
vue使用element-ui实现表单验证
2020/12/13 Vue.js
python新手经常遇到的17个错误分析
2014/07/30 Python
Python httplib模块使用实例
2015/04/11 Python
python使用邻接矩阵构造图代码示例
2017/11/10 Python
numpy使用fromstring创建矩阵的实例
2018/06/15 Python
pandas 空的dataframe 插入列名的示例
2018/10/30 Python
对Python获取屏幕截图的4种方法详解
2019/08/27 Python
tensorflow 只恢复部分模型参数的实例
2020/01/06 Python
Python模块常用四种安装方式
2020/10/20 Python
整理HTML5的一些新特性与Canvas的常用属性
2016/01/29 HTML / CSS
创造美妙香氛体验:Aera扩散器和香水
2018/11/25 全球购物
香港彩色隐形眼镜在线商店:Stunninglens(全球免费送货)
2019/05/10 全球购物
班长岗位职责
2013/11/10 职场文书
集团公司党的群众路线教育实践活动工作总结
2014/03/03 职场文书
节能宣传周活动总结
2014/05/08 职场文书
倡议书的写法
2014/08/30 职场文书
乡镇民主生活会发言材料
2014/10/20 职场文书
2015年三万活动总结
2015/03/25 职场文书
win10输入法不见了只能打出字母怎么解决?
2022/08/05 数码科技