在做这个功能时候,我参考的是网易注册(http://reg.163.com/reg/reg.jsp?product=urs)中的邮箱栏目所实现的功能与效果。这个功能的目的是使用户在填写邮箱栏目的过程中,在带有邮箱后缀名的菜单的提示下,可以不需要完整输入自己的注册邮箱,达到方便、快捷、友好的效果。在做这个功能的时候,需要充分站在使用者的角度,看怎样设计能够最符合通常情况下人们的使用习惯,又怎样设计反而会让用户感到不便。先来看看功能实现的演示效果图:
在线演示:http://jsfiddle.net/vudr00xc/embedded/result/
①初始状态,邮箱栏目未获得焦点时
以及鼠标点击后获得焦点时
②以空白字符( space , tab ) 以及@开头时,不出现提示菜单
③输入有效字符时,提示下拉菜单出现,用户输入的内容自动添加进菜单,并且第一条提示栏目获得高亮
④输入的字符第一次出现"@"时,输入的"@"并不加入提示菜单
⑤"@"之后出现有效字符时,就会同提示菜单中的邮件后缀从后缀首位起进行比较,把和用户输入的邮箱后缀不同的提示从菜单中去掉。同时过滤后的第一条提示获得高亮。在完全匹配之后,下拉菜单隐藏。
⑥用户删除邮件输入框中的字符时,呈现的效果顺序是⑤图3--->⑤图2---> ⑤图1---> ④图
⑦按下键盘方向键向上或向下使菜单相应提示高亮
⑧鼠标划过菜单提示时,原先的高亮消失,鼠标划过的栏目获得高亮;鼠标移开,保持之前鼠标划过的栏目高亮,直到用户继续输入字符,栏目失去高亮,同时第一条可见的提示高亮
⑨点击高亮提示或者高亮处回车,自动填充邮箱元素,选择完成,菜单收起
⑩在下拉菜单展开时,鼠标点击页面任何元素,菜单收起
注:此功能不包括正则验证邮箱格式。
本功能没有用到什么复杂的知识点,只有简单的JS字符串的匹配 ( match )、位置检索 ( indexOf ) 、截取 ( substr ) 以及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 엔진이 내부적으로 작동하는 방식을 이해하는 것은 개발자에게 중요합니다. 1) 엔진의 워크 플로에는 구문 분석, 컴파일 및 실행; 2) 실행 프로세스 중에 엔진은 인라인 캐시 및 숨겨진 클래스와 같은 동적 최적화를 수행합니다. 3) 모범 사례에는 글로벌 변수를 피하고 루프 최적화, Const 및 Lets 사용 및 과도한 폐쇄 사용을 피하는 것이 포함됩니다.

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

Python과 JavaScript는 커뮤니티, 라이브러리 및 리소스 측면에서 고유 한 장점과 단점이 있습니다. 1) Python 커뮤니티는 친절하고 초보자에게 적합하지만 프론트 엔드 개발 리소스는 JavaScript만큼 풍부하지 않습니다. 2) Python은 데이터 과학 및 기계 학습 라이브러리에서 강력하며 JavaScript는 프론트 엔드 개발 라이브러리 및 프레임 워크에서 더 좋습니다. 3) 둘 다 풍부한 학습 리소스를 가지고 있지만 Python은 공식 문서로 시작하는 데 적합하지만 JavaScript는 MDNWebDocs에서 더 좋습니다. 선택은 프로젝트 요구와 개인적인 이익을 기반으로해야합니다.

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

실제 세계에서 JavaScript의 응용 프로그램에는 서버 측 프로그래밍, 모바일 애플리케이션 개발 및 사물 인터넷 제어가 포함됩니다. 1. 서버 측 프로그래밍은 Node.js를 통해 실현되며 동시 요청 처리에 적합합니다. 2. 모바일 애플리케이션 개발은 재교육을 통해 수행되며 크로스 플랫폼 배포를 지원합니다. 3. Johnny-Five 라이브러리를 통한 IoT 장치 제어에 사용되며 하드웨어 상호 작용에 적합합니다.

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

PhpStorm 맥 버전
최신(2018.2.1) 전문 PHP 통합 개발 도구

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

SublimeText3 영어 버전
권장 사항: Win 버전, 코드 프롬프트 지원!

Eclipse용 SAP NetWeaver 서버 어댑터
Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.
