首页 > 代码库 > 原生js写的一个弧形菜单插件
原生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 =http://www.mamicode.com/ []; 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 .topMenu14 {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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。