原生js写的一个弧形菜单插件
弧形菜单是一种半弧式或者全弧形菜单,是一种不同于传统横向或者竖向菜单形式的菜单。最近在网上看到好多人写出了这种效果,于是也尝试自己写了一个。
实现方式:原生态js
主要结构:
1.参数合并
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];
}
}
这个结构把构造函数传入的参数来更新到默认参数上
2.弧形位置设置
一:左上角 left,top
二: 左下角 left,bottom
三:右上角 right,top
四:右下角 right,bottom
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);
}
这段代码主要实现的是,根据传入参数中的主菜单按钮的位置计算出对哪些属性(left,top...)进行赋值,根据子菜单个数计算出弧度,再更加参数中子菜单的展开半径计算出各个子菜单展开时的位置。然后创建子菜单dom,为子菜单配置文字,类名,并添加到dom中来.
3.子菜单展开动画和主按钮通过设定的触发机制来绑定
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]();
});
}
};
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 animate(domObj, animateObj, speed) {//动画方法 domobj是所有需要执行动画的dom对象集合,animateObj是对应动画dom的动画参数,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();
}
原生js实现动画有点坑爹,而且js进行算术计算的时候精度不是特别高,当然采用了一些办法解决和弥补
需要用到的样式,样式采用的css3的,兼容性不行,但是主要为了练习的是js,样式可以根据喜好自由切换
#menuBox .topMenu, #menuBox .Menu{display: block;width: 50px;height: 50px;
background-color: red;
border-radius: 25px;
text-align: center;
line-height: 50px;
font-family: 微软雅黑;
font-size: 14px;
color: #fff;
position: absolute;
display: none;
} #menuBox .topMenu
{
z-index: 99999;
display: block;
}
#menuBox .slefclass {//自定义样式
width:50px;
height:50px;
background-color:#00ff21;
}
页面调用方式
<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写的一个弧形菜单插件的更多相关文章
- 用canvas和原生js写的一个笨鸟先飞的小游戏(暂时只有一个关卡)
其中一个画布背景是一张图片,还有小鸟,两个管子的图片.暂时不知道怎么附上去就不添加了.这里只有源代码,css和js都是在html写着的,感觉比他们的容易吧,hah <!DOCTYPE html& ...
- 原生JS写了一个小demo,根据输入的数字生成不同背景颜色的小方块儿~
昨天练习写了这个小demo,个人觉得通过设置定位元素left和top的值,来实现换行的功能,这种方法很巧妙~ 另外,如下代码中的随机颜色的获取,还请各位前辈多多指教:需要改进的地方:或者有没有更好的方 ...
- 原生js写的一个当前年份日期星期和时间的显示
话不多说,所有代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type& ...
- 原生js写的一个简单slider
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 原生 js 写分页
欢迎留言或者加本人QQ172360937咨询 这段代码是用原生 js 写的一个分页的效果 <!doctype html> <html lang="en"> ...
- 原生JS写的ajax函数
参照JQuery中的ajax功能,用原生JS写了一个ajax,功能相对JQuery要少很多,不过基本功能都有,包括JSONP. 调用的方式分为两种: 1. ajax(url, {}); 2. ajax ...
- 原生js写一个无缝轮播图插件(支持vue)
轮播图插件(Broadcast.js) 前言:写这个插件的原因 前段时间准备用vue加上网易云的nodejs接口,模拟网易云音乐移动端.因为想自己写一遍所有的代码以及加固自己的flex布局,所以没有使 ...
- 用原生js写一个"多动症"的简历
用原生js写一个"多动症"的简历 预览地址源码地址 最近在知乎上看到@方应杭用vue写了一个会动的简历,觉得挺好玩的,研究一下其实现思路,决定试试用原生js来实现. 会动的简历实现 ...
- 用原生JS写移动动画案例及实际应用
js很强大 相信很多人都知道,那么它有哪些强大之处呢?有兴趣的人可以去查查,这里就不赘述了,因为不在本片文章讨论的范围. 我们要讲的是怎么用原生JS写移动动画?我们先举一个最简单的动画例子,很多网站的 ...
随机推荐
- Android开发学习总结——Android开发的一些相关概念(转)
一.什么是3G.4G 1995年问世的第一代模拟制式手机(1G)只能进行语音通话. 1996到1997年出现的第二代GSM.CDMA等数字制式手机(2G)便增加了接收数据的功能 3G指的是第三代移 ...
- [HA]负载均衡:HAPROXY与KEEPALIVED强强联合
第一步:更改系统控制配置文件,同意分配虚拟IP(VIP) /etc/sysctl.conf net.ipv4.ip_nonlocal_bind=1 <pre style="word-w ...
- POJ 3579- Median
Description Given N numbers, X1, X2, ... , XN, let us calculate the difference of every pair of n ...
- HDU1160(LIS)
主题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1160 题意:求体重下降.速度添加的样例最多有多少个 依据体重降序排一下,然后求速度的最长上升子序列 , ...
- Azure File Service in IIS
微软Azure的Storage套件中提供了新的服务File Service,让我们运行在Azure中的程序都能共享存储,一个存储账号共享的没有上线,但每个共享的上限是5G.由于File Service ...
- 离robots.txt启动网络爬虫之旅
要成为一个网络爬虫或搜索引擎(在这里,共同蜘蛛)它不会陌生,在搜索引擎爬虫的第一个文件或者访问该网站上浏览robots.txt该.robots.txt文件讲述了蜘蛛server哪些文件要观看正在. 当 ...
- EMVTag系列5《8E 持卡人验证方法(CVM)名单》
L: var. up to 252 -R(需求):数据必须存在,在读应用数据过程中,终端不检查 依照优先顺序列出卡片应用支持的全部持卡人验证方法 注:一个应用中能够有多个CVM列表,比如一个用于国内交 ...
- 一张地图告诉你,只JavaScript不够!
这将是JavaScript语法,你真的会一JavaScript嘛.看看这个图片!超好用JavaScript一本书的摘录游.熊儿.快去学习! 版权声明:本文博客原创文章.博客,未经同意,不得转载.
- Light OJ 1341 Aladdin and the Flying Carpet Pollard_rho整数分解+DFS
进入a b 多少努力p, q 使p*q == a && p < q && p >= b 直接大整数分解 然后dfs所有可能的解决方案劫持 #include ...
- 初识Java——(Java学习笔记一)
冯诺依曼体系结构 JAVA核心优势:跨平台---通过JVM(java虚拟机)来实现 JVM:Java虚拟机的一种规范 标示符:只能以下划线.美元符号($).字母.数字组成,不能以数字开 ...