基于jQuery的email suggest插件

  最近项目中有表单提交的地方需要用户填写邮箱,PM(产品经理)和运营都强烈要求在用户填写邮箱的时候出现suggest列表,简化用户输入的填写流程。我考虑了下,这个应该也是经常会用到的功能,细心的朋友可能会发现好多登录或者其他有表单提交的地方,比如搜狐白社会登录,我的搜狐登录等等都有这个功能,所以为了方便以后使用,索性写一个jQuery插件出来好了。

  这里不对具体代码做详解,只讲述实现思路和流程。首先有一份默认配置defaults

 1 // 默认参数配置
 2         defaults = {
 3             sugClass: 'ema-sug',
 4             domains: [
 5                 'sohu.com',
 6                 '163.com',
 7                 '126.com',
 8                 '139.com',
 9                 'sina.com',
10                 'qq.com',
11                 'gmail.com'
12             ]
13         }

sugClass是用户为suggest添加样式和作为插件内容js钩子使用的,domains是suggest列表内容,如果用户使用插件时候没有传递参数就会使用默认配置

插件内部有一个EmailSug构造函数,每次调用插件时候都会新创建一个EmailSug的实例,每个实例有自己的属性和配置

 1 function EmailSug(elem, options) {
 2         this.$field = $(elem); 
 3         this.options = $.extend(true, {}, defaults, options);
 4         this._defaults = defaults;
 5         this._domains = this.options.domains;
 6         // 当前选中元素下标
 7         this.selectedIndex = 0;
 8 
 9         this.init();
10     }

当创建实例时候会执行初始化函数,初始化函数调用了事件绑定方法

init: function() {
    this.addEvent();      
}

事件绑定方法对input元素进行了keyup blur事件的绑定,分别在用户输入内容时候进行suggest更新和blur时候关闭suggest提示

 1 addEvent: function() {
 2             var 
 3                 // 当前上下文
 4                 that = this,
 5 
 6                 // 
 7                 value;
 8 
 9             this.$field.on('keyup.ema', function(e) {
10                 value = $.trim(this.value);
11 
12                 if (value) {
13                     that.create(this, value);
14 
15                     that.doSelect(e.keyCode);
16                 } else {
17                     that.hide();
18                 }
19             }).on('blur.ema', function() {
20                 setTimeout(function() {
21                     that.hide(); 
22                 }, 200);
23             });
24         }

blur事件处理必须要使用setTimeout处理下,因为在用户通过鼠标点击suggest的某一个元素时候会触发input的blur事件,如果不做setTimeout处理会点击不到要选择的元素

  1 create: function(elem, value) {
  2             var 
  3                 // 
  4                 that = this,
  5 
  6                 arr,
  7 
  8                 len,
  9 
 10                 // 
 11                 fragment,
 12 
 13                 //  
 14                 ul = [],
 15                 
 16                 // 
 17                 offset,
 18 
 19                 left,
 20                 
 21                 top,
 22                 
 23                 width,
 24 
 25                 height,
 26 
 27                 style,
 28                 
 29                 // 左右边框 
 30                 borderWidth = 2;
 31 
 32             elem = $(elem);
 33             offset = elem.offset();
 34 
 35             width = elem.outerWidth(true) - borderWidth;
 36             height = elem.outerHeight(true);
 37             left = offset.left; 
 38             top = offset.top + height;
 39             style = 'left: ' + left + 'px; top: ' + top + 'px;  ' + width + 'px; border: 1px solid #e2e2e2; border-top: 0; display: none';
 40 
 41             // 
 42             fragment = $('<div class="' + this.options.sugClass + '-wrapper" style="' + style + '" />');
 43             ul.push('<ul class="' + this.options.sugClass + '-list">');
 44 
 45             arr = this.filter(value, this._domains);
 46             len = arr.length;
 47             $.each(arr, function(i, domain) {
 48                 var 
 49                     //  
 50                     _class = that.options.sugClass + '-item';
 51 
 52                 if (that.selectedIndex > len - 1) {
 53                     if (i === 0) {
 54                         _class += ' active';
 55 
 56                         that.selectedIndex = 0;
 57                     }
 58                 } else {
 59                     if (i === that.selectedIndex) {
 60                         _class += ' active';
 61                     } 
 62                 } 
 63 
 64                 ul.push('<li class="' + _class + '" data-index="' + i + '">' + value.replace(/@.*/, '') + '@' + domain  + '</li>'); 
 65             });
 66 
 67             ul.push('</ul>');
 68             ul = ul.join('');
 69 
 70             if (this.$suggest) {
 71                 this.$suggest.empty();
 72                 this.$suggest.append(ul);
 73             } else {
 74                 fragment.append(ul);
 75 
 76                 // 显示到页面
 77                 $('body').append(fragment);
 78                 this.$suggest = fragment;
 79 
 80                 /// 
 81                 this.$suggest.on('mouseenter click', '.' + this.options.sugClass + '-item', function(e) {
 82                     var lis,
 83                     
 84                         li;
 85 
 86                     li = $(this);
 87                     lis = li.parent().children();
 88 
 89                     if (e.type === 'mouseenter') {
 90                         li.addClass('active').siblings().removeClass('active');   
 91 
 92                         that.selectedIndex = $.inArray(this, lis);
 93                     } else {
 94                         // 当前选中
 95                         that.$field.val(lis.eq(that.selectedIndex).text());
 96 
 97                         // 隐藏email sug
 98                         that.hide();
 99                     }
100                 });
101             }
102 
103             // 
104             this.show();
105         }

create方法调用了filter方法根据用户输入的内容对配置参数domains进行过滤筛选,返回跟用户输入匹配的数组,然后创建suggest列表并选中某一个元素,根据input元素的位置对suggest进行定位,最后渲染到页面并显示。每个实例只会创建一个suggest元素,每次根据用户输入的内容更新列表

 1 // 
 2         filter: function(value, arr) {
 3             var 
 4                 // 
 5                 start,
 6             
 7                 suffix,
 8                 
 9                 r = [];
10 
11             start = value.indexOf('@');
12             if (start > -1) {
13                 suffix = value.substring(start + 1);
14 
15                 $.each(arr, function(i, str) {
16                     if (str.indexOf(suffix) > -1) {
17                         r.push(str); 
18                     }
19                 });
20             } else {
21                 r = arr;
22             }
23 
24             return r;
25         }

filter方法,实现逻辑很好理解

 1 doSelect: function(keyCode) {
 2             var 
 3                 //
 4                 elems = $('.' + this.options.sugClass + '-item', this.$suggest),
 5 
 6                 //  
 7                 min = 0,
 8 
 9                 // 
10                 max = elems.length - 1; 
11                 
12             switch (keyCode) {
13                 case 13:
14                     // 回车选中当前已选项
15                     $('li.active', this.$suggest).trigger('click');
16 
17                     // 下标重置
18                     this.selectedIndex = 0;
19 
20                     break;
21                     // 向上
22                 case 38:
23                     this.selectedIndex --;
24 
25                     if (this.selectedIndex < min) {
26                         this.selectedIndex = max;
27                     } 
28 
29                     elems.removeClass('active').eq(this.selectedIndex).addClass('active'); 
30                     break;
31                     // 向下 
32                 case 40:
33                     this.selectedIndex ++;
34 
35                     if (this.selectedIndex > max) {
36                         this.selectedIndex = min;
37                     }
38 
39                     elems.removeClass('active').eq(this.selectedIndex).addClass('active'); 
40                     break;
41                 default:
42                     break;
43             }       
44         }

doSelect方法用户处理用户的键盘操作,Up Down Enter Esc这些按键处理

 1 show: function() {
 2             if (this.$suggest) {
 3                 this.$suggest.show(); 
 4             }
 5         }
 6 
 7 hide: function() {
 8             if (this.$suggest) {
 9                 this.$suggest.hide(); 
10             }
11         }

show和hide方法就是简单的最suggest进行显示和隐藏操作

实现很简单吧,源码不超过300行。可能实现有不合理或者不完善的地方欢迎指正~

最后附上demo地址和源码

原文地址:https://www.cnblogs.com/typeof/p/4673445.html