最近项目中有表单提交的地方需要用户填写邮箱,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: ‘ + 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地址和源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>jQuery插件email suggest - demo</title>
<link href="http://files.cnblogs.com/files/typeof/base.css" rel=stylesheet type=text/css >
<style type="text/css">
.page {
padding: 20px 10px;
}
.page .email {
width: 350px;
height: 30px;
line-height: 30px;
border: 1px solid #e2e2e2;
padding-left: 10px;
font-size: 14px;
}
.ema-sug-wrapper {
position: absolute;
background: #fff;
text-align: left;
}
.ema-sug-wrapper .ema-sug-list .ema-sug-item {
font-size: 14px;
height: 25px;
line-height: 25px;
padding-left: 10px;
color: #333;
}
.ema-sug-wrapper .ema-sug-list .ema-sug-item.active {
background: #ff4800;
cursor: pointer;
color: #fff;
}
</style>
<script src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.min.js"> </script>
<script src="http://files.cnblogs.com/files/typeof/email-sug.js"> </script>
</head>
<body>
<div class="page">
<input type="text" class="email" />
</div>
<script>
$(‘.email‘).emailSug({
sugClass: ‘ema-sug‘,
domains: [
‘sohu.com‘,
‘sogou.com‘,
‘163.com‘,
‘126.com‘,
‘139.com‘,
‘sina.com‘,
‘qq.com‘,
‘gmail.com‘
]
});
</script>
</body>
</html>