编程挑战--下拉菜单
最近有一个叫慕客网的学习平台,现在很火。课程后面一般都会留有一道小题目,用来检测小伙伴们的学习结果。我看到有一个课程还不错,后面也跟了很多回复,不过感觉代码质量都不高,这可能和课程定位有关,如果你有信心写的更好,不妨来挑战一下。有兴趣的同学可以参考下面的链接:
课程地址:http://www.imooc.com/code/3631
我把题目要求再贴一下:
编程挑战
小伙伴们,根据所学知识,实现下图所示的菜单效果,实现点击菜单中的向下三角展开菜单,点击页面空白处收起菜单,按下键盘上的向上、向下方向键可以选中对应的选项,鼠标点击或按下回车键将当前高亮的选项内容设为菜单的标题
效果图: 在线演示:http://runjs.cn/detail/eoc1gtit
初始:
点击出现:
点击之后:
要求就这么多,我看到小伙伴们实现的都差不多,无非就是一个一个的循环邦定事件。完全是按提示做的,没有自己的创新。
下面我贴下自己的代码:
/** * 下拉菜单 * @param {string} id 节点#ID */ function Selecter (id) { var parent = document.getElementById(id), nodes = parent.children; this.parent = parent; this.title = nodes[0]; this.menu = nodes[1]; this.init(); } /** * 初始化 */ Selecter.prototype.init = function(){ var doc = document; this.selected = null; this.maxLen = this.menu.children.length; doc.addEventListener('click',this,false); doc.addEventListener('keydown',this,false); this.menu.addEventListener('mouseover',this,false); this.menu.addEventListener('mouseout',this,false); } /** * 事件处理 * @param {object} event 事件对象 */ Selecter.prototype.handleEvent = function(event){ var target = event.target || event.srcElement; switch(target.nodeName){ //点击三角时 case 'CITE': this.menuShow(); break; // 滑过滑过、离开、点击每个选项时 case 'A': this.removeLight(); this.selected = target; this.menuUpdate(); this.hightLight(); if(event.type=='click'){ this.menuHide(); } break; // 点击页面空白处时 case 'HTML': this.menuHide(); break; //键盘操作 default: this.keydown(event.keyCode); break; } return } /** * 更新菜单值 */ Selecter.prototype.menuUpdate = function(){ this.title.innerHTML = this.selected.innerHTML; } /** * 高亮选中项 */ Selecter.prototype.hightLight = function(){ if(this.selected){ this.selected.style.backgroundColor = 'gray'; } } /** * 移除高亮 */ Selecter.prototype.removeLight = function(){ if(this.selected){ this.selected.style.backgroundColor = 'white'; } } /** * 显示菜单项 */ Selecter.prototype.menuShow = function(){ this.menu.style.display = 'block'; this.hightLight(); } /** * 隐藏菜单项 */ Selecter.prototype.menuHide = function(){ this.menu.style.display = 'none'; } /** * 取下一项 */ Selecter.prototype.next= function(){ var target = this.selected; var index = target ? target.getAttribute('selectid')-1 : -1; this.removeLight(); index = ++index % this.maxLen; this.selected = this.menu.children[index].children[0]; this.hightLight(); } /** * 取上一项 */ Selecter.prototype.prev = function(){ var target = this.selected; var index = target ? target.getAttribute('selectid')-1 : 1; this.removeLight(); index = --index < 0 ? 0 : index; this.selected = this.menu.children[index].children[0]; this.hightLight(); } /** * 键盘操作 * @param {number} code ASSIC码 */ Selecter.prototype.keydown = function(code){ switch(code){ case 40: //down this.next(); break; case 38://up this.prev(); break; case 13: this.menuUpdate(); this.menuHide(); break; default: break; } } //调用 window.onload=function(){ var menu = new Selecter('divselect'); }
我是以对象的方式进行编写的,这样写的好处有:
1:对于调用者来说,不需要关心下拉框内部的节点和实现逻辑。只要传入一个id就可以了。
2: 整个下拉菜单看成是一个对象,每次对菜单进行什么操作,在对象内部都可以进行存储。避免进行不必要的节点查询操作。
3: 事件邦在根节点上,通过冒泡进行监听,即节省代码又可以有效提高性能。
4:代码按功能进行编写,结构清晰,扩展和维护方便。
以上就是王婆卖瓜,欢迎吐糟。