• 原生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; 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          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+ 

    演示代码下载地址https://files.cnblogs.com/bob1314/webtest.rar

    生活总是催促我们向前!
  • 相关阅读:
    python中的编码与解码
    python中的迭代器
    python中高阶函数与装饰器(3)
    python中高阶函数与装饰器(2)
    python中高阶函数与装饰器
    python中几种常用的数据类型
    python 启航
    Python [习题] 字典排序
    SQL-TSQL
    SQL基础语句
  • 原文地址:https://www.cnblogs.com/bob1314/p/3895901.html
Copyright © 2020-2023  润新知