原生js寫的一個弧形菜單插件

弧形菜單是一種半弧式或者全弧形菜單,是一種不一樣於傳統橫向或者豎向菜單形式的菜單。最近在網上看到好多人寫出了這種效果,因而也嘗試本身寫了一個。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+ 

 

演示代碼下載地址http://files.cnblogs.com/bob1314/webtest.rar

相關文章
相關標籤/搜索