jQuery 实现自动填充邮箱功能(带下拉提示)


Posted in Javascript onOctober 14, 2014

在做这个功能时候,我参考的是网易注册(http://reg.163.com/reg/reg.jsp?product=urs)中的邮箱栏目所实现的功能与效果。这个功能的目的是使用户在填写邮箱栏目的过程中,在带有邮箱后缀名的菜单的提示下,可以不需要完整输入自己的注册邮箱,达到方便、快捷、友好的效果。在做这个功能的时候,需要充分站在使用者的角度,看怎样设计能够最符合通常情况下人们的使用习惯,又怎样设计反而会让用户感到不便。先来看看功能实现的演示效果图:

在线演示:http://jsfiddle.net/vudr00xc/embedded/result/

①初始状态,邮箱栏目未获得焦点时

jQuery 实现自动填充邮箱功能(带下拉提示)

以及鼠标点击后获得焦点时

jQuery 实现自动填充邮箱功能(带下拉提示)

②以空白字符( space , tab ) 以及@开头时,不出现提示菜单

jQuery 实现自动填充邮箱功能(带下拉提示)

③输入有效字符时,提示下拉菜单出现,用户输入的内容自动添加进菜单,并且第一条提示栏目获得高亮

jQuery 实现自动填充邮箱功能(带下拉提示)

④输入的字符第一次出现"@"时,输入的"@"并不加入提示菜单

jQuery 实现自动填充邮箱功能(带下拉提示)

⑤"@"之后出现有效字符时,就会同提示菜单中的邮件后缀从后缀首位起进行比较,把和用户输入的邮箱后缀不同的提示从菜单中去掉。同时过滤后的第一条提示获得高亮。在完全匹配之后,下拉菜单隐藏。

jQuery 实现自动填充邮箱功能(带下拉提示)

jQuery 实现自动填充邮箱功能(带下拉提示)

jQuery 实现自动填充邮箱功能(带下拉提示)

⑥用户删除邮件输入框中的字符时,呈现的效果顺序是⑤图3--->⑤图2---> ⑤图1---> ④图

⑦按下键盘方向键向上或向下使菜单相应提示高亮

jQuery 实现自动填充邮箱功能(带下拉提示)

⑧鼠标划过菜单提示时,原先的高亮消失,鼠标划过的栏目获得高亮;鼠标移开,保持之前鼠标划过的栏目高亮,直到用户继续输入字符,栏目失去高亮,同时第一条可见的提示高亮

jQuery 实现自动填充邮箱功能(带下拉提示)

⑨点击高亮提示或者高亮处回车,自动填充邮箱元素,选择完成,菜单收起

jQuery 实现自动填充邮箱功能(带下拉提示)

⑩在下拉菜单展开时,鼠标点击页面任何元素,菜单收起

注:此功能不包括正则验证邮箱格式。

本功能没有用到什么复杂的知识点,只有简单的JS字符串的匹配 ( match )、位置检索 ( indexOf ) 、截取 ( substr ) 以及jQuery选择器的应用等。更主要的是对功能的逻辑分析要思路清晰,以及思考如何设计能真正使用户操作简便。这个功能的事件主要包括:

jQuery 实现自动填充邮箱功能(带下拉提示)

代码分析:

HTML和CSS代码:

HTML

<div class="ipt">
   <input type="text" name="uemail" id="uemail" placeholder="请输入常用邮箱"/>
   <ul class="autoul"></ul>
</div>

CSS

.ipt{ width:218px;}/* 输入框外围div */
input{ margin:0; padding-left:15px; padding-right:15px; width:184px;}/* 输入框 */
ul.autoul{ /* 下拉菜单 */

  width:216px;
  margin:0px;
  margin-top:-5px;
  padding:0px;
  color:#666;
  border:1px solid #666;
  border-top:0;
  overflow:hidden;
}
ul.autoul li.autoli{ /* 下拉菜单li */

  height:30px;
  display:block;
  list-style-type:none;
  text-align:left;
  cursor:pointer;
  font-size:14px;
  line-height:30px;
  padding-left:15px;
  padding-right:15px;
  overflow:hidden;
  /*当对象内文本溢出时显示省略标记*/
  text-overflow:ellipsis; 
}
.lihover{ /* 下拉菜单li高亮样式 */

  background-color:#eee;
}
span{ padding-right:2px;}/* li下文字 */
.showli{ display:block;}/* 经过过滤的li的样式 */

在DOM加载完毕后,初始化邮件列表并隐藏下拉菜单,JS代码片段:

$(function(){

  //初始化邮箱列表
  var mail = new Array("sina.com","126.com","163.com","gmail.com","qq.com","vip.qq.com","hotmail.com","sohu.com","139.com","vip.sina.com","21cn.cn","189.cn","sina.cn");

  //把邮箱列表加入下拉
  for(var i=0;i<mail.length;i++){
  
    var $liElement = $("<li class=\"autoli\"><span class=\"ex\"></span><span class=\"at\">@</span><span class=\"step\">"+mail[i]+"</span></li>");

    $liElement.appendTo("ul.autoul");
  }

  //下拉菜单初始隐藏
  $(".autoul").hide();
  
  //其他事件..........
});

输入框$("#uemail")的keyup和keydown事件是该功能的主要事件,输入字符时之所以用keyup事件而不用keydown事件是因为keyup事件在用户将键盘按键抬起时触发,是整个按键动作的最后阶段,所以在抬起按键时能看到相应的动作即实时看到输入的字符;而使用keydown事件时,只有在下一次按下键盘按键时才能看到上一次按下按键触发的动作,所以keydown事件在通过键盘获得页面控制方面用的比较多,因此在使用键盘方向键↑↓选择菜单提示时使用keydown事件。

//在邮箱输入框输入字符
 $("#uemail").keyup(function(){
 
    //........
 })

邮件输入框$("#uemail")的keyup事件:

①有输入的按键,使输入框有长度( 因为删除事件也是判断匹配以及长度,所以只需要添加删除事件特有的动作,而不必在此处排除删除事件 )

if(event.keyCode!=38 && event.keyCode!=40 && event.keyCode!=13){

      //菜单展现,需要排除空格开头和"@"开头
      if( $.trim($(this).val())!="" && $.trim(this.value).match(/^@/)==null ) {

        $(".autoul").show();
        //同时去掉原先的高亮,把第一条提示高亮
        if($(".autoul li.lihover").hasClass("lihover")) {
          $(".autoul li.lihover").removeClass("lihover");
        }
        $(".autoul li:visible:eq(0)").addClass("lihover");
      }else{//如果为空或者"@"开头
        $(".autoul").hide();
        $(".autoul li:eq(0)").removeClass("lihover");
      }

      //把输入的字符填充进提示,有两种情况:1.出现"@"之前,把"@"之前的字符进行填充;2.出现第一次"@"时以及"@"之后还有字符时,不填充
      //出现@之前
      if($.trim(this.value).match(/[^@]@/)==null){//输入了不含"@"的字符或者"@"开头

        if($.trim(this.value).match(/^@/)==null){
          //不以"@"开头
          $(this).next().children("li").children(".ex").text($(this).val());
        }
      }else{

        //输入字符后,第一次出现了不在首位的"@"
        //当首次出现@之后,有2种情况:1.继续输入;2.没有继续输入
        //当继续输入时
        var str = this.value;//输入的所有字符
        var strs = new Array();
        strs = str.split("@");//输入的所有字符以"@"分隔
        $(".ex").text(strs[0]);//"@"之前输入的内容
        var len = strs[0].length;//"@"之前输入内容的长度
        if(this.value.length>len+1){

          //截取出@之后的字符串,@之前字符串的长度加@的长度,从第(len+1)位开始截取
          var strright = str.substr(len+1);

          //正则屏蔽匹配反斜杠"\"
          if(strright.match(/[\\]/)!=null){
            strright.replace(/[\\]/,"");
            return false;
          }

          //遍历li
          $("ul.autoul li").each(function(){

            //遍历span
            //$(this) li
            $(this).children("span.step").each(function(){

              //@之后的字符串与邮件后缀进行比较
              //当输入的字符和下拉中邮件后缀匹配并且出现在第一位出现
              //$(this) span.step
              if($("ul.autoul li").children("span.step").text().match(strright)!=null && $(this).text().indexOf(strright)==0){
                //class showli是输入框@后的字符和邮件列表对比匹配后给匹配的邮件li加上的属性
                $(this).parent().addClass("showli");
                //如果输入的字符和提示菜单完全匹配,则去掉高亮和showli,同时提示隐藏
                if(strright.length>=$(this).text().length){
                  $(this).parent().removeClass("showli").removeClass("lihover").hide();
                }
              }else{
                $(this).parent().removeClass("showli");
              }
              if($(this).parent().hasClass("showli")){
                $(this).parent().show();
                $(this).parent("li").parent("ul").children("li.showli:eq(0)").addClass("lihover");
              }else{
                $(this).parent().hide();
                $(this).parent().removeClass("lihover");
              }
            });
          });
        }else{
          //"@"后没有继续输入时
          $(".autoul").children().show();
          $("ul.autoul li").removeClass("showli");
          $("ul.autoul li.lihover").removeClass("lihover");
          $("ul.autoul li:eq(0)").addClass("lihover");
        }
      }
}//有效输入按键事件结束

②按键为backspace(8)或是delete(46)

if(event.keyCode == 8 || event.keyCode == 46){
 
   $(this).next().children().removeClass("lihover");
   $(this).next().children("li:visible:eq(0)").addClass("lihover");
 }//删除事件结束

③按键为方向键↑(38)

if(event.keyCode == 38){
       //使光标始终在输入框文字右边
      $(this).val($(this).val());
 }//方向键↑结束

④按键为回车键(13)

if(event.keyCode == 13){

      if($("ul.autoul li").is(".lihover")) {

        $("#uemail").val($("ul.autoul li.lihover").children(".ex").text() + "@" + $("ul.autoul li.lihover").children(".step").text());
      }

      $(".autoul").children().hide();
      $(".autoul").children().removeClass("lihover"); 
      $("#uemail").focus();//回车后输入栏获得焦点
}

至此keyup事件结束。

#("#uemail")的keydown事件

$("#uemail").keydown(function(){

  if(event.keyCode == 40){
    //按键为↓时....
  }

  
  if(event.keyCode == 38){
   //按键为↑时....
  } 
})

⑤按键为方向键 ↓ (40)

if(event.keyCode == 40){

      //当键盘按下↓时,如果已经有li处于被选中的状态,则去掉状态,并把样式赋给下一条(可见的)li
      if ($("ul.autoul li").is(".lihover")) {

        //如果还存在下一条(可见的)li的话
        if ($("ul.autoul li.lihover").nextAll().is("li:visible")) {

          if ($("ul.autoul li.lihover").nextAll().hasClass("showli")) {

            $("ul.autoul li.lihover").removeClass("lihover")
                .nextAll(".showli:eq(0)").addClass("lihover");
          } else {

            $("ul.autoul li.lihover").removeClass("lihover").removeClass("showli")
                .next("li:visible").addClass("lihover");
            $("ul.autoul").children().show();
          }
        } else {

          $("ul.autoul li.lihover").removeClass("lihover");
          $("ul.autoul li:visible:eq(0)").addClass("lihover");
        }
      } 
}

⑥按键为方向键 ↑ (38)

if(event.keyCode == 38){

      //当键盘按下↓时,如果已经有li处于被选中的状态,则去掉状态,并把样式赋给下一条(可见的)li
      if($("ul.autoul li").is(".lihover")){

        //如果还存在上一条(可见的)li的话
        if($("ul.autoul li.lihover").prevAll().is("li:visible")){


          if($("ul.autoul li.lihover").prevAll().hasClass("showli")){

            $("ul.autoul li.lihover").removeClass("lihover")
                .prevAll(".showli:eq(0)").addClass("lihover");
          }else{

            $("ul.autoul li.lihover").removeClass("lihover").removeClass("showli")
                .prev("li:visible").addClass("lihover");
            $("ul.autoul").children().show();
          }
        }else{

          $("ul.autoul li.lihover").removeClass("lihover");
          $("ul.autoul li:visible:eq("+($("ul.autoul li:visible").length-1)+")").addClass("lihover");
        }
      }else{

        //当键盘按下↓时,如果之前没有一条li被选中的话,则第一条(可见的)li被选中
        $("ul.autoul li:visible:eq("+($("ul.autoul li:visible").length-1)+")").addClass("lihover");
      }
}

至此keydown事件结束。

⑦当鼠标点击下拉菜单的具体一条内容时

$(".autoli").click(function(){
   
     $("#uemail").val($(this).children(".ex").text()+$(this).children(".at").text()+$(this).children(".step").text());
     $(".autoul").hide();
 });
   //鼠标点击下拉菜单具体内容事件结束

⑧当鼠标点击document时,下拉隐藏

$("body").click(function(){
   
     $(".autoul").hide();
 });
 //鼠标点击document事件结束

⑨鼠标划过li时

$("ul.autoul li").hover(function(){

    if($("ul.autoul li").hasClass("lihover")){

      $("ul.autoul li").removeClass("lihover");
    }
    $(this).addClass("lihover");
  });

至此,功能完成。

Javascript 相关文章推荐
兼容IE和FF的js脚本代码小结(比较常用)
Dec 06 Javascript
两种不同的方法实现js对checkbox进行全选和反选
May 13 Javascript
JavaScript将XML转成JSON的方法
Mar 12 Javascript
JS实现模拟风力的雪花飘落效果
May 13 Javascript
关于JS中setTimeout()无法调用带参函数问题的解决方法
Jun 21 Javascript
js enter键激发事件实例代码
Aug 17 Javascript
Ionic2开发环境搭建教程
Aug 20 Javascript
jQuery+C#实现参数RSA加密传输功能【附jsencrypt.js下载】
Jun 26 jQuery
Webpack实战加载SVG的方法
Dec 26 Javascript
[原创]js实现保存文本框内容为本地文件兼容IE,chrome,火狐浏览器
Feb 14 Javascript
2020京东618叠蛋糕js脚本(亲测好用)
Jun 02 Javascript
通过实例解析jQ Ajax操作相关原理
Sep 23 Javascript
js网页右下角提示框实例
Oct 14 #Javascript
兼容主流浏览器的jQuery+CSS 实现遮罩层的简单代码
Oct 14 #Javascript
从数据库读取数据后将其输出成html标签的三种方法
Oct 13 #Javascript
JavaScript使用循环和分割来替换和删除元素实例
Oct 13 #Javascript
javascript实现分栏显示小技巧附图
Oct 13 #Javascript
jquery引用方法时传递参数原理分析
Oct 13 #Javascript
form.submit()不能提交表单的错误原因及解决方法
Oct 13 #Javascript
You might like
实用函数7
2007/11/08 PHP
memcached 和 mysql 主从环境下php开发代码详解
2010/05/16 PHP
PHP URL参数获取方式的四种例子
2014/02/28 PHP
PHP中使用imagick生成PSD文件缩略图教程
2015/01/26 PHP
PHP使用递归生成文章树
2015/04/21 PHP
PHP导入导出Excel代码
2015/07/07 PHP
WordPres对前端页面调试时的两个PHP函数使用小技巧
2015/12/22 PHP
深入理解Javascript闭包 新手版
2010/12/28 Javascript
纯JS实现五子棋游戏兼容各浏览器(附源码)
2013/04/24 Javascript
两个数组去重的JS代码
2013/12/04 Javascript
javascript在子页面中函数无法调试问题解决方法
2014/01/17 Javascript
通过JS动态创建一个html DOM元素并显示
2014/10/15 Javascript
jquery 表单验证之通过 class验证表单不为空
2015/11/02 Javascript
js面向对象之常见创建对象的几种方式(工厂模式、构造函数模式、原型模式)
2015/11/09 Javascript
Vue 短信验证码组件开发详解
2017/02/14 Javascript
用Fundebug插件记录网络请求异常的方法
2019/02/21 Javascript
小程序rich-text组件如何改变内部img图片样式的方法
2019/05/22 Javascript
js实现登录拖拽窗口
2020/02/10 Javascript
微信小程序学习总结(四)事件与冒泡实例分析
2020/06/04 Javascript
原生JS实现微信通讯录
2020/06/18 Javascript
npm ci命令的基本使用方法
2020/09/20 Javascript
Python模块文件结构代码详解
2018/02/03 Python
python 重定向获取真实url的方法
2018/05/11 Python
python用pandas数据加载、存储与文件格式的实例
2018/12/07 Python
python实现诗歌游戏(类继承)
2019/02/26 Python
对Python强大的可变参数传递机制详解
2019/06/13 Python
python提取log文件内容并画出图表
2019/07/08 Python
python中struct模块之字节型数据的处理方法
2019/08/27 Python
基于PyTorch的permute和reshape/view的区别介绍
2020/06/18 Python
Python爬虫使用bs4方法实现数据解析
2020/08/25 Python
CSS3 实现的火焰动画
2020/12/07 HTML / CSS
Melijoe时尚童装德国官网:Melijoe德国
2016/09/03 全球购物
《钱学森》听课反思
2014/03/01 职场文书
巾帼志愿者活动方案
2014/08/17 职场文书
大型公益活动策划方案
2014/08/20 职场文书
学习杨善洲同志先进事迹心得体会
2016/01/23 职场文书