學習例項索引原生js的手風琴選單 註釋詳解
阿新 • • 發佈:2018-12-17
這個程式碼我刪除了它底部的那個QQ,微博這些,只用了手風琴選單部分,原版來源點選開啟連結
我還是個JS新手,可能註釋很多地方都寫得很邋遢,不簡潔明瞭,有錯誤的地方也希望大家可以幫我指出來,修正我的思維誤區,謝謝了。
function CreateList() { this.oWrap = document.createElement("div");//建立了一個div 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 + ") <a href=\"" + project[i].href + "\" target=\"_blank\">" + project[i].text + "</a>" //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()最初建立的那個div裡 this.oWrap aData.shift()//刪除原來的aData[0],以前的aData[1]就會變成現在的aData[0] } this.oWrap.id = "wrap";//為this.oWrap這個div加一個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: div#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<obj.offsetHeight obj.iSpeed = obj.iSpeed > 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的div的子類一遍,如果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,div,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>