弧形菜單是一種半弧式或者全弧形菜單,是一種不一樣於傳統橫向或者豎向菜單形式的菜單。最近在網上看到好多人寫出了這種效果,因而也嘗試本身寫了一個。css
實現方式:原生態jshtml
主要結構:css3
1.參數合併web
1 var defaultPra = { 2 mainMenuId: "ArcMenu",//主菜單id 3 menuBoxId:"menuBox",//菜單包裹id 4 position: "",//弧形菜單 5 customPosition:"0,0",//自定義位置 6 speed: 200,//展開速度 7 radius: 200,//放射距離, 8 menuRange: 90,//菜單展開範圍 9 childMenuClass: "Menu",//子菜單默認類 10 triggerWay: "click",//觸發方式 11 showStatus:false,//子菜單當前狀態 12 childMenu: [//子菜單內容 13 { linkContent: "菜單一", linkUrl: "http://www.baidu.com", className: "Menu" }, 14 { linkContent: "菜單二", linkUrl: "http://www.baidu.com", className: "Menu" }, 15 { linkContent: "菜單三", linkUrl: "http://www.baidu.com", className: "Menu" }, 16 { linkContent: "菜單四", linkUrl: "http://www.baidu.com", className: "Menu" }, 17 { linkContent: "菜單五", linkUrl: "http://www.baidu.com", className: "Menu" }, 18 ] 19 }
1 for (var i in defaultPra) { 2 if (options[i]) { 3 defaultPra[i] = options[i]; 4 } 5 }
這個結構把構造函數傳入的參數來更新到默認參數上chrome
2.弧形位置設置app
一:左上角 left,topdom
二: 左下角 left,bottom函數
三:右上角 right,top測試
四:右下角 right,bottom動畫
1 var childLen = defaultPra.childMenu.length;//子菜單個數 2 var circular = 2 * Math.PI / 360 * (parseFloat(defaultPra.menuRange)/childLen); //分割後的弧度 3 var positionStr = defaultPra.position ? defaultPra.position : "left,top";//主按鈕位置 4 var customPositionStr = /^\d+,\d+$/.test(defaultPra.customPosition) ? defaultPra.customPosition : "0,0";//自定義位置 5 var positionVal = defaultPra.position.split(","); 6 var customPositionVal = defaultPra.customPosition.split(",") 7 mainMenu.style[positionVal[0]] = customPositionVal[0]+"px";//初始化主菜單的位置 8 mainMenu.style[positionVal[1]] = customPositionVal[1]+"px";//初始化主菜單的位置 9 for (var i = 0; i < childLen; i++) {//循環初始化子菜單,添加屬性,類別等,並添加到菜單包裹框裏 10 var domA = document.createElement("a"); 11 var currChild = defaultPra.childMenu[i]; 12 domA.innerHTML = currChild.linkContent; 13 domA.setAttribute("href", currChild.linkUrl); 14 domA.className = defaultPra.mainMenuId + defaultPra.childMenuClass + " " + defaultPra.childMenuClass+" "+ currChild.className; 15 domA.style[positionVal[0]] = customPositionVal[0] + "px";; 16 domA.style[positionVal[1]] = customPositionVal[1] + "px"; 17 menuBox.appendChild(domA); 18 }
這段代碼主要實現的是,根據傳入參數中的主菜單按鈕的位置計算出對哪些屬性(left,top...)進行賦值,根據子菜單個數計算出弧度,再更加參數中子菜單的展開半徑計算出各個子菜單展開時的位置。而後建立子菜單dom,爲子菜單配置文字,類名,並添加到dom中來.
3.子菜單展開動畫和主按鈕經過設定的觸發機制來綁定
1 function addEvent (obj, type, fn) {//兼容的綁定事件的方法 2 if (obj.addEventListener){ 3 obj.addEventListener(type, fn, false); 4 }else if (obj.attachEvent) { 5 obj["e" + type + fn] = fn; 6 obj.attachEvent("on" + type, function () { 7 obj["e" + type + fn](); 8 }); 9 } 10 };
1 addEvent(mainMenu, defaultPra.triggerWay, function () { 2 var len = defaultPra.childMenu && defaultPra.childMenu.length || 0; 3 var data = []; 4 for (var i = 0; i < len; i++) {//循環生產動畫所需的目標位置樣式值對象 5 var obj = new Object(); 6 var v0=parseFloat( mainMenu.style[positionVal[0]]); 7 var v1=parseFloat(mainMenu.style[positionVal[1]]); 8 if (defaultPra.showStatus) { 9 obj[positionVal[1]] = v1; 10 obj[positionVal[0]] = v0; 11 } else { 12 obj[positionVal[0]] = defaultPra.radius * Math.cos(i * circular) + v0;//計算橫向座標 13 obj[positionVal[1]] = defaultPra.radius * Math.sin(i * circular) + v1;//計算縱向座標 14 } 15 data.push(obj); 16 } 17 currAnimate = animate(menuBox.getElementsByClassName(defaultPra.mainMenuId + defaultPra.childMenuClass), data, defaultPra.speed); 18 defaultPra.showStatus = !defaultPra.showStatus;//修改當前菜單展開狀態 19 });
1 function animate(domObj, animateObj, speed) {//動畫方法 domobj是全部須要執行動畫的dom對象集合,animateObj是對應動畫dom的動畫參數,speed是動畫速度 2 var lenAni = animateObj && animateObj.length || 0; 3 var i = 0; 4 var trimer = 0 5 var aniArr = []; 6 this.animateCollect = []; 7 this.stop = function () { 8 for (var j = 0; j < this.animateCollect.length; j++) { 9 this.animateCollect[j].stop(); 10 } 11 } 12 this.start = function () { 13 this.animateCollect = func(); 14 } 15 var func = function () { 16 aniArr[i] = new Object(); 17 aniArr[i].isAnimate = false; 18 aniArr[i].trimer = 0; 19 aniArr[i].interval = setInterval(function () { 20 if (i == lenAni) { 21 return aniArr; 22 } 23 aniArr[i].isAnimate = true; 24 for (var k in animateObj[i]) { 25 if (aniArr[i].trimer == 0) { 26 domObj[i][k] = parseFloat(domObj[i].style[k]) 27 } 28 domObj[i].style.display = "block"; 29 domObj[i].style[k] = (parseFloat(domObj[i].style[k]) + ((parseFloat(animateObj[i][k]) - domObj[i][k] ) / ((parseFloat(speed) /1 )))) + "px"; 30 } 31 aniArr[i].trimer += 1; 32 if (aniArr[i].trimer >= speed) { 33 clearInterval(aniArr[i].interval); 34 aniArr[i].isAnimate = false; 35 aniArr[i].trimer = 0; 36 i++; 37 func();//遞歸執行下一個動畫 38 } 39 },1); 40 aniArr[i].stop = function () {//動畫結束 41 clearInterval(aniArr[i].interval); 42 aniArr[i].isAnimate = false; 43 aniArr[i].trimer = 0; 44 45 } 46 47 }; 48 this.start(); 49 }
原生js實現動畫有點坑爹,並且js進行算術計算的時候精度不是特別高,固然採用了一些辦法解決和彌補
須要用到的樣式,樣式採用的css3的,兼容性不行,可是主要爲了練習的是js,樣式能夠根據喜愛自由切換
1 #menuBox .topMenu, #menuBox .Menu{display: block;width: 50px;height: 50px; 2 background-color: red; 3 border-radius: 25px; 4 text-align: center; 5 line-height: 50px; 6 font-family: 微軟雅黑; 7 font-size: 14px; 8 color: #fff; 9 position: absolute; 10 display: none; 11 } 12 13 #menuBox .topMenu 14 { 15 z-index: 99999; 16 display: block; 17 } 18 #menuBox .slefclass {//自定義樣式 19 width:50px; 20 height:50px; 21 background-color:#00ff21; 22 }
頁面調用方式
<div id="menuBox"><!--該id默認狀況下是menuBox,如需更改,須要在js調用中配置--> <a id="MenuParent" >菜單</a> <a id="MenuParent1" >菜單</a> <a id="MenuParent2" >菜單</a> <a id="MenuParent3" >菜單</a> <a id="MenuParent4" >菜單</a> <a id="MenuParent5" >菜單</a> </div> <script> ArcMenu({ mainMenuId: "MenuParent", position: "left,bottom", customPosition: "500,400",//自定義位置 childMenu: [//子菜單的節點數據,可自定義樣式class,也可不指定。默認Menu { linkContent: "菜單一", linkUrl: "http://www.baidu.com", className: "Menu" }, { linkContent: "菜單二", linkUrl: "http://www.baidu.com", className: "Menu" }, { linkContent: "菜單三", linkUrl: "http://www.baidu.com", className: "Menu" }, { linkContent: "菜單四", linkUrl: "http://www.baidu.com", className: "Menu" }, { linkContent: "菜單五", linkUrl: "http://www.baidu.com", className: "Menu" }, { linkContent: "菜單六", linkUrl: "http://www.baidu.com", className: "Menu" }, { linkContent: "菜單七", linkUrl: "http://www.baidu.com", className: "Menu" }, { linkContent: "菜單八", linkUrl: "http://www.baidu.com", className: "Menu" }, { linkContent: "菜單九", linkUrl: "http://www.baidu.com", className: "Menu" }, ], radius: 100,//放射距離, menuRange: 360,//菜單展開範圍 speed:22//展開速度 }) ArcMenu({ mainMenuId: "MenuParent1", position: "left,top", speed:50 }) ArcMenu({ mainMenuId: "MenuParent2", position: "right,top" }) ArcMenu({ mainMenuId: "MenuParent3", position: "left,bottom" }) ArcMenu({ mainMenuId: "MenuParent4", position: "right,bottom" }) ArcMenu({ mainMenuId: "MenuParent5", position: "left,bottom", customPosition: "800,400", childMenu: [ { linkContent: "菜單一", linkUrl: "http://www.baidu.com", className: "slefclass" }, { linkContent: "菜單二", linkUrl: "http://www.baidu.com", className: "slefclass" }, { linkContent: "菜單三", linkUrl: "http://www.baidu.com", className: "slefclass" }, { linkContent: "菜單四", linkUrl: "http://www.baidu.com", className: "slefclass" }, { linkContent: "菜單五", linkUrl: "http://www.baidu.com", className: "slefclass" }, { linkContent: "菜單六", linkUrl: "http://www.baidu.com", className: "slefclass" }, { linkContent: "菜單七", linkUrl: "http://www.baidu.com", className: "slefclass" }, { linkContent: "菜單八", linkUrl: "http://www.baidu.com", className: "slefclass" }, { linkContent: "菜單九", linkUrl: "http://www.baidu.com", className: "slefclass" }, ], radius: 100,//放射距離, menuRange: 360,//菜單展開範圍 speed: 22 }) </script>
頁面調用的時候,傳入參數,能夠實現各類不一樣位置的效果。具體能夠看源碼,該封裝有不少能夠擴展的地方,好比能夠擴展展開的動畫效果,展開的形狀,初始化子菜單的狀態等等。後續會繼續完成。
頁面效果如上面的那個截圖
目前css只測試chrome ie9+