现在位置首页 / 前端开发 /正文

纯js圆形/环形/弧形导航菜单

作者: IT小兵 | 2014年8月7日| 热度:℃ | 评论: |参与:

在以前的文章[jQuery Scroll Path自定义轨迹路径插件--制作圆形动画循环组合导航菜单]插件。今天分享一个纯js写的圆形/环形/弧形导航菜单.

先看效果图:

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

实现方式:原生态js

主要结构:

1.参数合并

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

2.弧形位置设置

一:左上角 left,top

二: 左下角 left,bottom

三:右上角 right,top

四:右下角 right,bottom

根据传入参数中的主菜单按钮的位置计算出对哪些属性(left,top...)进行赋值,根据子菜单个数计算出弧度,再更加参数中子菜单的展开半径计算出各个子菜单展开时的位置。然后创建子菜单dom,为子菜单配置文字,类名,并添加到dom中来.

3.子菜单展开动画和主按钮通过设定的触发机制来绑定

原生js实现动画有点坑爹,而且js进行算术计算的时候精度不是特别高,当然采用了一些办法解决和弥补

需要用到的样式,样式采用的css3的,兼容性不行,但是主要为了练习的是js,样式可以根据喜好自由切换

源代码:

/********弧形菜单插件***************
 ********作者:决明子***************
 ***********************************/
var ArcMenu;
(function () {
    ArcMenu = function (options) {
        this.showStatus = false;
        this.initMenu = function () {
            var defaultPra = {
                mainMenuId: "ArcMenu",//主菜单id
                menuBoxId: "menuBox",//菜单包裹id
                position: "",//弧形菜单
                customPosition: "0,0",//自定义位置
                speed: 200,//展开速度
                radius: 200,//放射距离,
                menuRange: 90,//菜单展开范围
                childMenuClass: "Menu",
                triggerWay: "click",
                showStatus: false,
                childMenu: [//子菜单内容
                    { 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" },
                ]
            }
            for (var i in defaultPra) {
                if (options[i]) {
                    defaultPra[i] = options[i];
                }
            }
            var mainMenu = document.getElementById(defaultPra.mainMenuId);
            var menuBox = document.getElementById(defaultPra.menuBoxId);
            mainMenu.setAttribute("class", "topMenu")
            var childLen = defaultPra.childMenu.length;//子菜单个数
            var circular = 2 * Math.PI / 360 * (parseFloat(defaultPra.menuRange) / childLen); //分割后的弧度
            var positionStr = defaultPra.position ? defaultPra.position : "left,top";//主按钮位置
            var customPositionStr = /^\d+,\d+$/.test(defaultPra.customPosition) ? defaultPra.customPosition : "0,0";//自定义位置
            var positionVal = defaultPra.position.split(",");
            var customPositionVal = defaultPra.customPosition.split(",")
            mainMenu.style[positionVal[0]] = customPositionVal[0] + "px";
            mainMenu.style[positionVal[1]] = customPositionVal[1] + "px";
            for (var i = 0; i < childLen; i++) {
                var domA = document.createElement("a");
                var currChild = defaultPra.childMenu[i];
                domA.innerHTML = currChild.linkContent;
                domA.setAttribute("href", currChild.linkUrl);
                domA.className = defaultPra.mainMenuId + defaultPra.childMenuClass + " " + defaultPra.childMenuClass + " " + currChild.className;
                domA.style[positionVal[0]] = customPositionVal[0] + "px";;
                domA.style[positionVal[1]] = customPositionVal[1] + "px";
                menuBox.appendChild(domA);
            }
            addEvent(mainMenu, defaultPra.triggerWay, function () {
                var len = defaultPra.childMenu && defaultPra.childMenu.length || 0;
                var data = [];
                for (var i = 0; i < len; i++) {
                    var obj = new Object();
                    var v0 = parseFloat(mainMenu.style[positionVal[0]]);
                    var v1 = parseFloat(mainMenu.style[positionVal[1]]);
                    if (defaultPra.showStatus) {
                        obj[positionVal[1]] = v1;
                        obj[positionVal[0]] = v0;
                    } else {
                        obj[positionVal[0]] = defaultPra.radius * Math.cos(i * circular) + v0;
                        obj[positionVal[1]] = defaultPra.radius * Math.sin(i * circular) + v1;
                    }
                    data.push(obj);
                }
                currAnimate = animate(menuBox.getElementsByClassName(defaultPra.mainMenuId + defaultPra.childMenuClass), data, defaultPra.speed);
                defaultPra.showStatus = !defaultPra.showStatus;
            });
            function addEvent(obj, type, fn) {
                if (obj.addEventListener)
                    obj.addEventListener(type, fn, false);
                else if (obj.attachEvent) {
                    obj["e" + type + fn] = fn;
                    obj.attachEvent("on" + type, function () {
                        obj["e" + type + fn]();
                    });
                }
            };
            function animate(domObj, animateObj, speed) {
                var lenAni = animateObj && animateObj.length || 0;
                var i = 0;
                var trimer = 0
                var aniArr = [];
                this.animateCollect = [];
                this.stop = function () {
                    for (var j = 0; j < this.animateCollect.length; j++) {
                        this.animateCollect[j].stop();
                    }
                }
                this.start = function () {
                    this.animateCollect = func();
                }
                var func = function () {
                    aniArr[i] = new Object();
                    aniArr[i].isAnimate = false;
                    aniArr[i].trimer = 0;
                    aniArr[i].interval = setInterval(function () {
                        if (i == lenAni) {
                            return aniArr;
                        }
                        aniArr[i].isAnimate = true;
                        for (var k in animateObj[i]) {
                            if (aniArr[i].trimer == 0) {
                                domObj[i][k] = parseFloat(domObj[i].style[k])
                            }
                            domObj[i].style.display = "block";
                            domObj[i].style[k] = (parseFloat(domObj[i].style[k]) + ((parseFloat(animateObj[i][k]) - domObj[i][k]) / ((parseFloat(speed) / 1)))) + "px";
                        }
                        aniArr[i].trimer += 1;
                        if (aniArr[i].trimer >= speed) {
                            clearInterval(aniArr[i].interval);
                            aniArr[i].isAnimate = false;
                            aniArr[i].trimer = 0;
                            i++;
                            func();
                        }
                    }, 1);
                    aniArr[i].stop = function () {
                        clearInterval(aniArr[i].interval);
                        aniArr[i].isAnimate = false;
                        aniArr[i].trimer = 0;
                    }
                };
                this.start();
            }
        }
        this.initMenu();
    }
}())

页面调用方式:

<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


点击阅读本文所属分类的更多文章: 前端开发 。和高手一起交流:346717337
友荐云推荐

未注明转发、原文均为本站原创。分享本文请注明 原文链接

给您更多信息和帮助

在这里您可以找到更多:

技术交流群:346717337 Jquery插件交流

投稿:suchso@vip.qq.com

承接:企业网站门户/微网站/微商城/CMS系统/微信公众号运营/业务咨询

echarts教程系列
本月最热文章

微信扫一扫,徜徉悠嘻网,您的休闲乐园

微信公众号:快乐每一天

随机文章
标签

技术交流群:346717337

投稿:suchso@vip.qq.com

专业专注:企业网站门户/微网站/微商城/CMS系统/微信公众号运营/付费问题咨询