索引原生js的手风琴菜单注释详解(实例)
程序员文章站
2022-07-07 10:10:21
这个代码我删除了它底部的那个QQ,微博这些,只用了手风琴菜单部分
我还是个JS新手,可能注释很多地方都写得很邋遢,不简洁明了,有错误的地方也希望大家可以帮我指出来,修正我的思维误...
这个代码我删除了它底部的那个QQ,微博这些,只用了手风琴菜单部分
我还是个JS新手,可能注释很多地方都写得很邋遢,不简洁明了,有错误的地方也希望大家可以帮我指出来,修正我的思维误区,谢谢了。
function CreateList() { this.oWrap = document.createElement("p");//创建了一个p this.initialize.apply(this, arguments);//initialize 只不过是个变量,代表一个方法,叫什么名字都行。 this.click.call(this);//click也只是一个变量,代表一个方法,叫什么名字都行 /* call和apply的第一个实参是要调用函数的母对象,call方法是将所有参数罗列出来,而apply是将所有参 数放在一个数组中。这里有篇文章可以看看:https://blog.csdn.net/myhahaxiao/article/details/6952321*/ } /*这是另一篇有注释里写到的:www.bubuko.com/infodetail-1164722.html arguments就是构造函数接受的参数,构造函数调用时 new CreateList(aData[])传入的是一个数组 数组的每一个项都是json对象 json对象的格式为 project:[ { text:"测试文字", }, { text:"测试文字", href:"" } ] 每一个project数组的项对应一个DL----(对应无序列表的ul)-----自定义列表dl---dt--dd */ /*prototype 原型对象的作用,就是定义所有实例对象共享的属性和方法 相关文章:https://blog.csdn.net/jasonzds/article/details/53706958*/ CreateList.prototype = { initialize: function(aData) { //这个函数的主要目的是初始化 把dl dt dd 的数量、结构层次这些弄好 var oDl, oElem, project, i; while(aData[0]) {//aData[0]为真时,循环执行,代码往后走有一个aData.shift(),shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。 oDl = document.createElement("dl"); project = aData[0].project; for(i = 0; i < project.length; i++) {//从project遍历出新建dl下的dt和dd if(project[i].href) {//有href属性的为dd oElem = document.createElement("dd"); oElem.innerHTML = i + ") " + project[i].text + "" //innerHTML 添加内容 } else {//反之为dt oElem = document.createElement("dt"); oElem.innerHTML = project[i].text + " (" + (project.length - 1) + ")" } oDl.appendChild(oElem);//将oElem加入到oDl里,也就是把dt dd放在dl里 oDl.style.height = "31px"//将dl的高度设为31px; } this.oWrap.appendChild(oDl);//将新建的dl放到CreateList()最初创建的那个p里 this.oWrap aData.shift()//删除原来的aData[0],以前的aData[1]就会变成现在的aData[0] } this.oWrap.id = "wrap";//为this.oWrap这个p加一个id wrap document.body.appendChild(this.oWrap);//再将其加入到body里 }, click: function() {//这个函数主要是点击事件 var that = this; this.oWrap.onclick = function(event) {//点击事件的绑定 var oEv, oTarget, oParent, i; oEv = event || window.event;//在FireFox浏览器中,事件绑定的函数要获取到事件本身,需要从函数中传入,而IE等浏览器则可以直接使用event或者window.event得到事件本身。 oTarget = oEv.target || oEv.srcElement;//返回事件的目标节点,根据console.log(oTarget);可以得到该节点是dt oParent = oTarget.parentElement || oTarget.parentNode;//事件的目标节点的父节点,dl oParent.height = function() {//获取dl里的总高度 var iHeight = 0;//在这里用console.log( oParent.children[0].offsetHeight)==31其他的都是26 主要原因是要理解到offsetHeight的定义 然后去看css就知道为什么了 //HTMLElement.offsetHeight 是一个只读属性,它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。 for(i = 0;i < oParent.children.length; i++) iHeight += oParent.children[i].offsetHeight; return iHeight;//iHeight=dt像素高度+所有dd像素高度 }(); if(oTarget.tagName.toUpperCase() == "DT") {//如果是dt,当你的菜单是展开时,点dd就不会执行这段代码 var aSiblings = that.siblings(oParent), count, i;//siblings()往下翻,代码最后一个函数 for(count = i = 0; i < aSiblings.length; i++) {//对非点击的dl元素进行遍历,记住这里有一个循环,也就是为什么会有++count== aSiblings.length的原因 //第一个参数是dl 第二个是点击元素dt的像素高度 第三个是运动类型 第四个是匿名函数 //这个startMove是检测其他dl是否展开,如果展开就要对其进行收拢的操作 //匿名函数!=自执行匿名函数,匿名函数作为参数,在调用(将匿名函数作为参数的)函数里被调用执行了。 that.startMove(aSiblings[i], oTarget.offsetHeight, "buffer", function() { this.children[0].className = "";//这里的this代表的是aSiblings[i],也就是dl //这个if语句是对点击的dl进行操作 if(++count == aSiblings.length) {//当除点击事件在的dl所有dl的类名都为空时 if(oParent.offsetHeight == oTarget.offsetHeight) {//当点击事件所在菜单没有没有展开时 oTarget.className = "current"; //这个startMove是把点击事件所在菜单被展开 //看清第二个是传的参数是oParent.height that.startMove(oParent, oParent.height, "flex") } else {//当点击事件所在菜单展开时,这个startMove就把他收拢 that.startMove(oParent, oTarget.offsetHeight, "buffer", function() { oTarget.className = "" ; }) } } }) } } } }, startMove: function(obj, iTarget, type, callback) { var that = this;//这里的this 是指CreateList?{oWrap: p#wrap} clearInterval(obj.timer); obj.iSpeed = 0; obj.timer = setInterval(function() { that[type].call(that, obj, iTarget, callback) }, 30) }, buffer: function(obj, iTarget, callback) {//菜单的收拢 obj.iSpeed = (iTarget - obj.offsetHeight) / 5;//(1)当前没有任何菜单展开 或 点击的是菜单展开事件的dt时 iTarget==obj.offsetHeight,(2)有菜单的话(不为点击事件本来所在菜单),当循环到展开的那个菜单时iTarget 0 ? Math.ceil(obj.iSpeed) : Math.floor(obj.iSpeed); obj.offsetHeight == iTarget ? (clearInterval(obj.timer), callback && callback.call(obj)) : obj.style.height = obj.offsetHeight + obj.iSpeed + "px" //是第(1)种情况的时候,clearInterval(obj.timer) 被调用,if(callback){callback.call(obj)} //是第(2)种情况的时候,会一直到obj.offsetHeight == iTarget,也就是另一个菜单被收拢,clearInterval(obj.timer) 才会被调用,并if(callback){callback.call(obj)} }, flex: function(obj, iTarget, callback) {//打开菜单 obj.iSpeed += (iTarget - obj.offsetHeight) / 6; obj.iSpeed *= 0.75; if(Math.abs(iTarget - obj.offsetHeight) <= 1 && Math.abs(obj.iSpeed) <= 1) {/*abs() 方法可返回数的绝对值。*/ clearInterval(obj.timer); obj.style.height = iTarget + "px"; callback && callback.call(obj);//不要这一句程序也是正确的,不知道这句拿来做什么 } else { obj.style.height = obj.offsetHeight + obj.iSpeed + "px"; } }, siblings: function(element) {//这个函数就是找到所有的同级元素,并且返回一个数组 var aTmp = [], oParent = element.parentElement || element.parentNode, i; //这个for语句的意思是遍历,id为wrap的p的子类一遍,如果element != oParent.children[i],然后就把它放进 aTmp[]中,最后返回aTmp[] for(i = 0; i < oParent.children.length; i++) element != oParent.children[i] && aTmp.push(oParent.children[i]); return aTmp } };
html,css,js
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>手风琴菜单</title> <style> body,p,dl,dt,dd{margin:0;padding:0;} a:link,a:visited{color:#FFF;text-decoration:none;} a:hover{text-decoration:underline;} #wrap{width:350px;background:#FFF;border:12px solid #EEE;border-radius:10px;margin:10px auto 0;padding:5px 5px 4px;} #wrap dl{color:#FFF;overflow:hidden;background:#7CF;} #wrap dt,#wrap dd{padding-left:15px;border-bottom:1px solid #FFF;} #wrap dt{cursor:pointer;font-size:14px;background:#9C0;font:700 14px/30px Tahoma;} #wrap dt.current{background:#09F;} #wrap dd{background:#7CF;font:12px/25px Tahoma;}/*前者是font-size,后者是line-height*/ </style> <script src="js/CreateList.js"></script> <script> window.onload = function() { new CreateList([ { project: [{ text: "标题1" }, { text: "1", href: "1" }, { text: "2", href: "2" }] }, { project: [{ text: "标题2" }, { text: "1", href: "1" }, { text: "2", href: "2" }, { text: "3", href: "3" }, { text: "4", href: "4" },] }, { project: [{ text: "标题3" }, { text: "1", href: "1" }, { text: "2", href: "2" }, { text: "3", href: "3" }, { text: "4", href: "4" },] }, { project: [{ text: "标题4" }, { text: "1", href: "1" }, { text: "2", href: "2" }, { text: "3", href: "3" }, { text: "4", href: "4" },] } ]); }; </script> </head> <body></body> </html>
上一篇: aiepk2.exe进程是安全的程序吗 aiepk2是什么进程
下一篇: 男人不许喊痛