原生js写的一个弧形菜单插件

弧形菜单是一种半弧式或者全弧形菜单,是一种不同于传统横向或者竖向菜单形式的菜单。最近在网上看到好多人写出了这种效果,于是也尝试自己写了一个。

实现方式:原生态js

主要结构:

1.参数合并

 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    }

这个结构把构造函数传入的参数来更新到默认参数上

2.弧形位置设置

一:左上角 left,top

二: 左下角 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

原生js写的一个弧形菜单插件,布布扣,bubuko.com

时间: 2024-12-15 01:42:52

原生js写的一个弧形菜单插件的相关文章

原生JS写的一个书架式的图片缩放滚动展示特效代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <title>d

原生JS写了一个小demo,根据输入的数字生成不同背景颜色的小方块儿~

昨天练习写了这个小demo,个人觉得通过设置定位元素left和top的值,来实现换行的功能,这种方法很巧妙~ 另外,如下代码中的随机颜色的获取,还请各位前辈多多指教:需要改进的地方:或者有没有更好的方法. 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 <style type="text

原生js写的一个当前年份日期星期和时间的显示

话不多说,所有代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>当前时间显示 </title> </head> <body onload="startTime()"> <d

原生JS写的ajax函数

参照JQuery中的ajax功能,用原生JS写了一个ajax,功能相对JQuery要少很多,不过基本功能都有,包括JSONP. 调用的方式分为两种: 1. ajax(url, {}); 2. ajax({}); 调用的方法参照JQuery的ajax,只是 不需要写$.ajax ,只需要写 ajax 就可以了. 代码如下: !function () { var jsonp_idx = 1; return ajax = function (url, options) { if (typeof url

用原生JS写移动动画案例及实际应用

js很强大 相信很多人都知道,那么它有哪些强大之处呢?有兴趣的人可以去查查,这里就不赘述了,因为不在本片文章讨论的范围. 我们要讲的是怎么用原生JS写移动动画?我们先举一个最简单的动画例子,很多网站的左边或右边会有个分享的框,鼠标放上去就还移出一个列表,里面是要分享的地址.鼠标移开,就会移进去. 要实现这个效果要怎么做呢? 可以想一想,鼠标经过和鼠标离开很好理解 用onmousemove事件和onmouseout事件就能完成. 那移动动画呢?我们可以一步一步思考, 首先,一开始是这样的 完成移动

用jQuery写了一个模态框插件

用jQuery写了一个模态框插件 大家觉得下面的框框好看么, 水印可以去掉(这个任务交给你们了(- o -)~zZ); "info"框 $("div").confrimModal("<font color=\"green\">成功! </font>", {type:"info", themeColor: "#008B8B"}, true); "alert

用js写的一个路由

前几天在院子里看了一个大牛用js写了一个路由的,有一句代码一直不知道怎么回事,后来就自己写了一个,写的比较的粗糙,我觉得把面向对象的思想都搞得乱七八糟的,不过功能实现了. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>js实现路由</title> </head> <body> &

JS 学习制作一个二级菜单

1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title>菜单栏</title> 5 <script src="jquery/jquery-2.1.1.js"></script> 6 <script> 7 $(document).ready(function () {

原生js写的贪吃蛇网页版游戏

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>原生js写的贪吃蛇网页版游戏</title> </head> <body><div><A href="http://www.999jiujiu.com/">h