首页 web前端 H5教程 详解微博发言框的@功能

详解微博发言框的@功能

May 17, 2016 am 09:09 AM

经常使用微博的人会发现,当我们在输入框输入@然后敲一个人的名字,会弹出一个tip提示层,如图所示:

weibo.jpg



出于对这个功能的好奇,并抱着学习的态度,翻阅了一些资料后对这个Javascript进行了探讨和研究。
对这个功能进行分析如下:

1、确定光标的位置

2、textarea文本框里对字符串@的判断

3、tip的弹出事件

4、键盘的操作事件

5、ajax调用

6、文字的插入

......

当然还有其他的功能。

看着是不是感觉很复杂?没关系,我们一步一步的分析。

首先我们要确定textarea的光标位置。在W3C中,获取光标位置比较简单,可以用selectionStart和selectionEnd,IE浏览器不支持这2个属性 ,但是IE又一个document.selection对象,可以模拟实现相同的功能。代码如下:


  1. //先定义一个基本类,来设置一些全局变量
  2. function demonAt(opts) {
  3.     this.elem=opts.elem; //文本框
  4.     this.at= {};    //临时保存文本框内容截取属性
  5.     this.opt= {};
  6.     this.searched=""; //用于判断用户输入字符是否和前面一样,如果一样跳过ajax
  7.     this.url=opts.url;
  8.     this.index=1;
  9. }
  10. //微博的@功能
  11. demonAt.prototype= {
  12.     getCursor: function(elem) {
  13.         var _this=this;
  14.         var rangeData = {
  15.             start: 0,
  16.             end: 0,
  17.             text: ""
  18.         };
  19.         if(typeof(this.elem.selectionStart)=="number") {//W3C
  20. rangeData.start=this.elem.selectionStart;//光标起始位置
  21.             rangeData.end=this.elem.selectionEnd;//光标末尾位置
  22. rangeData.text=this.elem.value.substring(0,this.elem.selectionStart);//获取文本框value
  23.         } else if (document.selection) {//IE
  24.             var sRange=document.selection.createRange();
  25.             var oRange=document.body.createTextRange();
  26.             oRange.moveToElementText(this.elem);
  27.             rangeData.text=sRange.text;
  28.             rangeData.bookmark = sRange.getBookmark();
  29. for(i=0;oRange.compareEndPoints("StartToStart",sRange)
  30.                 if (this.elem.value.charAt(i) == '\r') {
  31.                     i ++;//IE的特殊处理,遇到enter键需要加1
  32.                 }
  33.             }
  34.             rangeData.start=i;
  35.             rangeData.end = rangeData.text.length + rangeData.start;
  36.             rangeData.text=this.elem.value.substring(0,i);
  37.         }
  38.         //alert(rangeData.text)
  39.         return rangeData;
  40.     },
  41.     setCursor: function(elem,start,end) {//设置光标
  42.         if(this.elem.setSelectionRange) {//W3C
  43.             this.elem.setSelectionRange(start,end);
  44.         } else if(this.elem.createRange) {//IE
  45.             var range=this.elem.createRange();
  46.             if(this.elem.value.length==rangeData.start) {
  47.                 range.collapse(false);
  48.                 range.select();
  49.             } else {
  50.                 range.moveToBookmark(rangeData.bookmark);
  51.                 range.select();
  52.             }
  53.         }
  54.     },
  55.     add: function(elem,txtData,nStart, nLen) {//插入文本参数操作的元素,数据,起始坐标位置,用户输入字符长度
  56.         //this.setCursor(this.elem,this.rangeData);
  57.         this.elem.focus();
  58.         var _range;
  59.         if(this.elem.setSelectionRange) {//W3C
  60.             _tValue=this.elem.value;//获取文本框内容
  61.             var _start = nStart - nLen,//设置光标起点光标的位置-离@的文本长度
  62.             _end = _start + txtData.length,//设置光标末尾,start+数据文字长度
  63.             _value=_tValue.substring(0,_start)+txtData+" "+_tValue.substring(nStart, this.elem.value.length);
  64.             this.elem.value=_value;
  65.             this.setCursor(this.elem,_end+1,_end+1);
  66.         } else if(this.elem.createTextRange) {
  67.             _range=document.selection.createRange();
  68.             _range.moveStart("character", -nLen);//移动光标
  69.             _range.text = txtData+" ";
  70.         }
  71.     }
  72. }
复制代码


自定义一个rangeData对象,保存光标的位置和textarea框内从光标位置到开始处的字符串;返回出来。这个对象在下面其他函数中会用到。根据光标位置的确定,可以书写文字插入函数add();有了上面的函数,我们可以对textarea框内@的字符判断,然后实现tip层定位和弹出,如果判断这个,我们可以用正则:

  1. var _reg=/@[^@\s]{1,20}$/g;
复制代码


那么定位呢,若在textarea内判断是不现实的,因为我们无法获取正确的left和top值,所以这里需要模拟一个div层,将div插入到body 中,定位到与textarea相同的位置,然后获取到textarea内的文字,进行字符串的拆分,加上标签元素,这样可以获取到正确的位置。说的有点绕了,看下面代码能更直观的表达。

  1. var _string=""+"@前面的文字"+""+"@"+""+"@后面的文字"+"";
复制代码


看到这句,很多人应该理解做法,将这段append到上诉定位的div中,这样,我们可以通过标签获取到offset值了。于是我们写下面的代码:


  1. demonAt.prototype= {
  2.     init: function() {//首先我们要初始化
  3.         var _body=$("body");
  4.         var _div=$("
    "),
  5.         _tip=$("
    ");
  6.         _body.append(_div);
  7.         _body.append(_tip);
  8.         var _left=$(this.elem).offset().left+"px",
  9.         _top=$(this.elem).offset().top+"px",
  10.         _width=$(this.elem).outerWidth()+"px",
  11.         _height=$(this.elem).outerHeight()+"px",
  12.         _lineHeight=$(this.elem).css("line-height"),
  13.         _style="position:absolute;overflow:hidden;z-index:-9999;line-height:"+_lineHeight+";width:"+_width+";height:"+_height+";left:"+_left+";top:"+_top;
  14.         _div.attr("style",_style);
  15.         this.inset();
  16.     },
  17.     getAt: function() {
  18.         var _rangeData=this.getCursor();
  19.         var k=_value=_rangeData.text.replace(/\r/g,"");//去掉换行符
  20.         var _reg=/@[^@\s]{1,20}$/g;//正则,获取value值后末尾含有@的并且在20字符内
  21.         var _string="";
  22.         if(_value.indexOf("@")>=
  23.         0&&_value.match(_reg)) {
  24.             var _postion=_rangeData.start;
  25.             var _oValue=_value.match(_reg)[0];//找到value中最后匹配的数据
  26.             var vReg=new RegExp("^"+_oValue+".*$","m");//跟数据匹配的正则   暂时保留
  27.             _value=_value.slice(0, _postion); //重写_value 字符串截取  从0截取到光标位置
  28.             if(/^@[a-zA-Z0-9\u4e00-\u9fa5_]+$/.test(_oValue)&& !/\s/.test(_oValue)) {
  29.                 this.at['m'] = _oValue = _oValue.slice(1);//用户输入的字符  如@颓废小魔,即"颓废小魔"
  30.                 this.at['l'] = _value.slice(0, -_oValue.length - 1); //@前面的文字
  31.                 this.at['r'] = k.slice(_postion - _oValue.length, k.length);//@后面的文字
  32.                 this.at['pos']=_postion;//光标位置
  33.                 this.at['len']=_oValue.length;//光标位置至@的长度,如 @颓废小魔,即"颓废小魔"的长度
  34.                 this.showTip(this.url)
  35.             } else {//alert(1)
  36.                 this.hiddenTip()
  37.             }
  38.         } else {
  39.             this.hiddenTip()
  40.         }
  41.     },
  42.     buidTip: function() {//创建tip,设置tip的位置
  43.         var _this=this;
  44.         $("#tWarp").empty();
  45.         var _string=""+this.format(this.at['l'])+""+"@"+""+this.format(this.at['r'])+"";
  46.         $("#tWarp").html(_string);
  47.         var _left=$("#tWarp cite").offset().left+"px",
  48.         _top=$("#tWarp cite").offset().top+parseInt($("#tWarp").css("line-height"))+"px";
  49.         if(parseInt(_top)>parseInt($("#tWarp").offset().top+$("#tWarp").height())) {
  50.             _top=$("#tWarp").offset().top+$("#tWarp").height()+"px";
  51.         }
  52.         $("#tipAt").css({
  53.             "left":_left,
  54.             "top":_top,
  55.             "display":"block"
  56.         });
  57.         $("#tipAt li").eq(1).addClass("on").siblings().removeClass("on");
  58.         _this.hover();
  59.         //取消keyup绑定,绑定keydown,键盘操作选择,避免与文本框的事件冲突
  60.         $(_this.elem).unbind('keyup').bind('keydown', function(e) {
  61.             return _this.keyMove(e);
  62.         });
  63.     },
  64.     hiddenTip: function() {
  65.         var _this=this;
  66.         $("#tipAt").css("display","none");
  67.         $("#tipAt li").unbind("click,mouseover");
  68.     }
  69. }
复制代码


然后我们添加键盘的操作,这里注意的是,我们在textarea输入文字的时候已经绑定keyup事件,为了避免事件多次绑定,tip的选择我们用keydown事件处理。

  1. demonAt.prototype= {
  2.     keyMove: function(e) {//键盘操作
  3.         var _this=this;
  4.         var _key=e.keyCode;
  5.         var _len=$("#tipAt li").length;
  6.         switch(_key) {
  7.             case 40:
  8.                 //下
  9.                 _this.index++;
  10.                 if(_this.index>_len-1) {
  11.                 _this.index=1;
  12.                 }
  13.                 _this.keyMoveTo(_this.index);
  14.                 //return false一定要加上,不然JS会继续进行调用keyHandler,从而绑定了keyup事件影响到键盘的keydown事件
  15.                 return false;
  16.                 break;
  17.             case 38:
  18.                 //上
  19.                 _this.index--;
  20.                 if(_this.index
  21.                 _this.index=_len-1;
  22.                 }
  23.                 _this.keyMoveTo(_this.index);
  24.                 return false;
  25.                 break;
  26.             case 13:
  27.                 //enter键
  28.                 var txtData=$(".on").text();
  29.                 _this.add(_this.elem,txtData,_this.at['pos'],_this.at['len'])
  30.                 _this.keyHandler()
  31.                 return false;
  32.                 break;
  33.             default:
  34.         };
  35.         _this.keyHandler();
  36.     },
  37.     keyHandler: function() {
  38.         var _this=this;
  39.         _this.index=1;
  40.         //enter键盘操作后重新绑定keyup
  41.         $(_this.elem).unbind("keydown").bind("keyup", function() {
  42.             _this.getAt();
  43.         })
  44.     },
  45.     keyMoveTo: function(index) {
  46.         $("#tipAt li").removeClass("on").eq(index).addClass("on");
  47.     }
  48. }
复制代码


然后添加tip的点击事件和hover事件。

  1. demonAt.prototype= {
  2.     inset: function() {//给li绑定事件,
  3.         var _this=this;
  4.         $("#tipAt").delegate("li","click", function() {//事件委托
  5.             if($(this).index()==0) {
  6.                 _this.elem.focus();
  7.                 return false;
  8.             } else {
  9.                 var txtData=$(this).text();
  10.                 _this.add(_this.elem,txtData,_this.at['pos'],_this.at['len'])
  11.                 _this.hiddenTip()
  12.             }
  13.         })
  14.     },
  15.     hover: function() {
  16.         //hover事件
  17.         var _this=this;
  18.         $("#tipAt li:not(:first)").hover( function() {
  19.             _this.index=$(this).index();
  20.             $(this).addClass("hover").siblings().removeClass("on hover")
  21.         }, function() {
  22.             $(this).removeClass("hover");
  23.         })
  24.     }
  25. }
复制代码

到这里,微博的@功能就已经全部讲解清楚了,希望各位可以清楚明白的了解。



转自我爱猫猫技术博客

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

<🎜>:泡泡胶模拟器无穷大 - 如何获取和使用皇家钥匙
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系统,解释
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆树的耳语 - 如何解锁抓钩
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1674
14
CakePHP 教程
1429
52
Laravel 教程
1333
25
PHP教程
1278
29
C# 教程
1257
24
H5代码:Web开发人员的最佳实践 H5代码:Web开发人员的最佳实践 Apr 16, 2025 am 12:14 AM

H5代码的最佳实践包括:1.使用正确的DOCTYPE声明和字符编码;2.采用语义化标签;3.减少HTTP请求;4.使用异步加载;5.优化图像。这些实践能提升网页的效率、可维护性和用户体验。

H5:网络标准和技术的发展 H5:网络标准和技术的发展 Apr 15, 2025 am 12:12 AM

Web标准和技术从HTML4、CSS2和简单的JavaScript演变至今,经历了显着的发展。 1)HTML5引入了Canvas、WebStorage等API,增强了Web应用的复杂性和互动性。 2)CSS3增加了动画和过渡功能,使页面效果更加丰富。 3)JavaScript通过Node.js和ES6的现代化语法,如箭头函数和类,提升了开发效率和代码可读性,这些变化推动了Web应用的性能优化和最佳实践的发展。

H5:如何增强网络上的用户体验 H5:如何增强网络上的用户体验 Apr 19, 2025 am 12:08 AM

H5通过多媒体支持、离线存储和性能优化提升网页用户体验。1)多媒体支持:H5的和元素简化开发,提升用户体验。2)离线存储:WebStorage和IndexedDB允许离线使用,提升体验。3)性能优化:WebWorkers和元素优化性能,减少带宽消耗。

了解H5代码:HTML5的基本原理 了解H5代码:HTML5的基本原理 Apr 17, 2025 am 12:08 AM

HTML5是构建现代网页的关键技术,提供了许多新元素和功能。1.HTML5引入了语义化元素如、、等,增强了网页结构和SEO。2.支持多媒体元素和,无需插件即可嵌入媒体。3.表单增强了新输入类型和验证属性,简化了验证过程。4.提供了离线和本地存储功能,提升了网页性能和用户体验。

解构H5代码:标签,元素和属性 解构H5代码:标签,元素和属性 Apr 18, 2025 am 12:06 AM

HTML5代码由标签、元素和属性组成:1.标签定义内容类型,用尖括号包围,如。2.元素由开始标签、内容和结束标签组成,如内容。3.属性在开始标签中定义键值对,增强功能,如。这些是构建网页结构的基本单位。

H5代码的基础:密钥元素及其目的 H5代码的基础:密钥元素及其目的 Apr 23, 2025 am 12:09 AM

HTML5的关键元素包括、、、、、等,用于构建现代网页。1.定义头部内容,2.用于导航链接,3.表示独立文章内容,4.组织页面内容,5.展示侧边栏内容,6.定义页脚,这些元素增强了网页的结构和功能性。

H5和HTML5之间的连接:相似性和差异 H5和HTML5之间的连接:相似性和差异 Apr 24, 2025 am 12:01 AM

H5和HTML5是不同的概念:HTML5是HTML的一个版本,包含新元素和API;H5是基于HTML5的移动应用开发框架。HTML5通过浏览器解析和渲染代码,H5应用则需要容器运行并通过JavaScript与原生代码交互。

HTML5和H5:了解常见用法 HTML5和H5:了解常见用法 Apr 22, 2025 am 12:01 AM

HTML5和H5没有区别,H5是HTML5的简称。1.HTML5是HTML的第五个版本,增强了网页的多媒体和交互功能。2.H5常用于指代基于HTML5的移动网页或应用,适用于各种移动设备。

See all articles