版权声明:本文为博主原创文章,如要转载或者其余合做请邮件告知我将会在24小时内回复,邮箱:lengroubao@163.com
在实际开发开发中咱们会用到各类浏览器、HTML、JS等提供的原生的组件/接口,可是这样并不必定知足咱们的要求,因此咱们须要本身写一些咱们须要的组件。 日常咱们会常常用`select` 标签作下拉选项,不过这个只能选择不能手动输入,固然网上也有很强大的select2插件,若是只要输入和选择两个功能的话那么强大的功能并非咱们须要的。这篇文章咱们就来写一个简单实用的selectjavascript
需求css
需求很简单咱们要作的是两个功能 输入和下拉选择,为了交互体验更好,咱们须要作动画和事件。保证交互的流畅。并且咱们还须要作一些简单的验证来检测非法输入。html
交互vue
首先,咱们要先明白要写那些事件,经过以前的gif 咱们能够看到 一共有三个事件,获取焦点,焦点事情,点击事件。 除了事件,还须要作一些过分,若是对兼容性没有严格要求的话(IE低版本)过分用CSS就行了。若是对兼容性有严格要求那么就用JS来写。这里的是用CSS3的 `transition` 来作一个0.3秒的过渡java
验证jquery
除了交互还要验证是否输入了非法字符,这里最合适的是用正则表达式来作,咱们这个例子是验证正整数 `/^[1-9]\d*$/` 若是是要验证邮箱`/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/` 验证只能输入数字和英文的 `/^[0-9a-zA_Z]+$/` 若是不会正则表达式能够网上百度,基本上你须要的表达式都能查到。web
具体实现正则表达式
知道要作什么了 大家就直接上代码吧,这里JS是重点,全部我先贴html结构和JS,CSS最后放。HTML结构编程
<div class="canInpSelection"> <input type="text" class="canInp" name=""> <ul class="select" data-height=""> <li data-value='1'>1</li> <li data-value='2'>2</li> <li data-value='3'>3</li> <li data-value='4'>4</li> </ul> </div>
这里的li列表能够写死能够动态渲染。 data-value是用来存数据的,好比数据的ID或者其余的什么。 data-height是用来存ul的高度的,主要是过分动画须要浏览器
JS 注意 这里依赖JQ的选择器和data()方法 能够直接用百度的CDN
<script type="text/javascript" src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>
获取焦点事件(focus)
这个事件的逻辑是 获取焦点->若是用户还没输入那么把输入框清空方便用户输入 ->根据列表数计算UL高度存入data-height属性里->而后设置高度,CSS会自动出现过分效果
$('body').on('focus ','.canInpSelection',function () { var ul =$(this).find('.select') if($(this).find('input').val() == 0){ $(this).find('input').val('') } if(ul.data('height') == ''){ var h= ul.find('li').length *25 ul.data('height',h) } var ch = ul.css('height') var dh = ul.data('height') if(ch == '0px'){ ul.css('height',dh) } })
失去焦点事件(blur)
这里的逻辑很简单 若是用户没有输入就设置默认值0,不然就判断,而后`异步`执行关闭下拉事件。
$('body').on('blur ','.canInpSelection',function () { var ul =$(this).find('.select') var val = $(this).find('input').val() if(val== ''){ $(this).find('input').val('0') }else{ var ex = /^[1-9]\d*$/; if(!ex.test(val)){ $(this).find('input').val('0') // tips.error('请输入正整数') alert('请输入正整数') } } setTimeout(function () { ul.css('height',0) },100) })
点击事件(click)
点击事件就是赋值加关闭
$('body').on('click ','.select li',function () { var value = $(this).data('value') $(this).parent().prev().val(value) $(this).parent().css('height','0') })
解BUG-异步编程
在事情焦点事件里最后的关闭必定要用异步来作(setTimeout),不然会出BUG,由于JS是单线程的,必须先执行完blur才能执行click,可是执行blur的时候会关闭UL,致使click没法触发(由于咱们这里有300毫秒的过分因此会有一部分能触发click一部分不能)。为了保证交互 那段关闭UL的代码也必须存在,全部只能用异步来作。 等个100毫秒,在关闭,在这100毫秒里足够JS处理完click的事件了。 有兴趣的同窗能够试试不用异步会发生什么,或者将100毫秒缩短到1毫秒? 若是对异步感兴趣的同窗能够百度“js 异步编程”。之后我也会写一篇关于异步的博文。
组件化
对于组件化我以为要根据实际工做环境来讲: 若是用框架的能够用框架的方式来,好比NG的directive或者vue的directive之类的。 若是不用框架用了underscore之类的工具库,也能够用_.template来写通用的。 若是都不用,也能够用面向对象的方式抽出来。 这个组件化,根据实际开发环境来,仁者见仁智者见智。 若是 要写成组件的话,正则表达式最好做为参数传进去。我这里只提供思路,并不难。
CSS
其实CSS没啥 能够根据本身公司的风格随便改。这里最主要的就是下面这段CSS
-webkit-transition: height ease-out .3s; transition: height ease-out .3s;
transition height 就是根据height的编程作过分 用时300毫秒。 值得注意的是 transition 所根据的属性必须是具体值,好比auto就不能够。并且这个元素也必须存在,否则也不会有效果。 下面是完整CSS
div,ul,li,input{ box-sizing: border-box; } ul{ list-style-type: none; } .canInpSelection{ position: relative; width: 200px; } .canInp{ width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border-color: #ddd; border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075); box-shadow: inset 0 1px 1px rgba(0,0,0,.075); -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s; -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; transition: border-color ease-in-out; box-shadow: none; -webkit-box-shadow: none; -webkit-tap-highlight-color: rgba(0,0,0,0); } .select{ position: absolute; top: 33px; left: 0px; right: 0px; background-color: #fff; background-image: none; z-index: 10; text-align: left; height:0; overflow: hidden; -webkit-transition: height ease-out .3s; transition: height ease-out .3s; border-radius: 0 0 5px 5px; padding: 0; margin: 0; } .select li{ height: 25px; line-height: 25px; cursor: pointer; border: 1px solid #ccc; border-top: 0; border-bottom: 0; width: 100%; padding-left: 10px; } .select li:last-child{ border-bottom:1px solid #ccc; } .select li:first-child{ border-top:1px solid #ccc; }
总结
纵观整个组件,思路理清楚了其实并不难,我以为最有意思的就是用`setTimeout` 来作异步处理了。