摘要:前言上一篇面试的总结,大家看的还行,因为量很大,错误在所难免,希望大家发现错误了可以告诉我一声,我的邮箱是,一个小前端的希望。
前言
上一篇面试的总结,大家看的还行,因为量很大,错误在所难免,希望大家发现错误了可以告诉我一声,我的邮箱是236490794@qq.com,一个小前端的希望。
我们老样子直接先上效果图再开始今天的分享
这个项目的github可以看一看
界面组成
逻辑分析
最终实现
从上图中,我们可以看出界面主要分为menu和item2块,其中menu的动画是自传,item的动画是位移,然后这里我们通过绝对布局的方式将整个控件定位在四个角落
.menu_container {
position: absolute;
z-index: 100;
border-radius: 50%;
transition-duration: 400ms;
text-align: center;
border: #efefef 3px solid;
box-shadow: aliceblue 1px 1px 1px;
}
.menu_item {
position: absolute;
border-radius: 50%;
z-index: 99;
border: #efefef 3px solid;
text-align: center;
box-shadow: aliceblue 1px 1px 1px;
}
这里我将这个控件几个属性独立出来,方便下次开发,其中包含,menu的背景,整个控件在屏幕的哪个角落,menu的宽高,item距离menu位移的距离,menu的背景色,及item的背景色,item的相关内容则由数据来控制,具体的我们直接在下方的实现里来讲解。
这里我用代码加注释的方式,帮助大家理解,template我简单的带过一下
核心实现
通过分析可以得出,每个item的偏移量应该为
横向x:基础值 * sin(角度值)
纵向y:基础值 * cos(角度值)
角度值:(数组的长度-1-当前的下标) 每一块所占的角度 弧度表示
弧度表示:2 * Math.PI / 360
export default {
...
props: {//开放的属性,方便自定义
menuSrc: {
default: require("../assets/menu.png")
},
position: {
default: "LT"//可选择LT、LB、RT、RB4个角落
},
width: {
default: 50,
},
baseDistance: {
default: 150,
},
menuBg: {
default: "white"
},
itemBg: {
default: "white"
},
menuItems: {
type: Array,
}
},
data() {
return {
openFlag: false,//展开合并标志
operators: ["+", "+"],//用于记录展开时动画XY方向
}
},
mounted() {
//根据props初始化各内容的各种style
this.$refs.menuHome.style.width = this.width + "px";
this.$refs.menuHome.style.height = this.width + "px";
this.$refs.menuHome.style.lineHeight = this.width + "px";
this.$refs.menuHome.style.background = this.menuBg;
this.menuItems.forEach((item) => {
let el = document.getElementById(item.name);
el.style.width = `${this.width * 0.8}px`;
el.style.height = `${this.width * 0.8}px`;
el.style.lineHeight = `${this.width * 0.8}px`;
el.style.background = this.itemBg;
});
//根据position,选择不同的定位
switch (this.position) {
case "LT":
this.$refs.menuHome.style.left = "20px";
this.$refs.menuHome.style.top = "20px";
this.menuItems.forEach((item) => {
let el = document.getElementById(item.name);
el.style.left = "26px";
el.style.top = "26px";
});
this.operators = ["+", "+"];
break;
...
}
},
methods: {
toggleMenu() {
if (!this.openFlag) {//合并时,点击展开操作
this.menuItems.forEach((item, index) => {
this.toggleMenuTransition(item.name, index, false)
});
//menu本身转一周
this.$refs.menuHome.style.transform = "rotate(360deg)";
} else {
this.menuItems.forEach((item, index) => {
this.toggleMenuTransition(item.name, index, true)
});
//menu恢复
this.$refs.menuHome.style.transform = "rotate(0)";
}
this.openFlag = !this.openFlag;
},
toggleMenuTransition(name, index, revert) {
let oneArea = 90 / (this.menuItems.length - 1);//每一块所占的角度
let axisX = Math.sin((this.menuItems.length - 1 - index) * oneArea * 2 * Math.PI / 360);//横坐标所偏移的比例
let axisY = Math.cos((this.menuItems.length - 1 - index) * oneArea * 2 * Math.PI / 360);//纵坐标所便宜的比例
let el = document.getElementById(name);//若所传的name一直,会报错。
let that = this;
if (!revert) {
setTimeout(function () {
el.style.transitionDuration = "200ms";
el.style.transform = `translate(${that.operators[0]}${that.baseDistance * axisX}px,${that.operators[1]}${that.baseDistance * axisY }px)`;//进行动画
}, index * 100)//通过定时器的方式,达到一个一个弹出来的效果
} else {
//item恢复
el.style.transitionDuration = "200ms";
el.style.transform = `translate(0,0)`;
}
},
clickMenu(item, index) {
//暴露方法给父组件,进行点击事件的操作
this.$emit("clickMenu", item, index)
}
}
}
再父组件中引入就可以大功告成啦,先跳一会儿吧,燃烧你的卡路里
引入组件
import toggleMenu from "./toggleMenu"
在 components声明
components: {
toggleMenu
},
template中使用
menuItems: [//name和src必填,且name唯一否则会报错
{name: "menu1", src: require("../assets/emoji.png")},
{name: "menu2", src: require("../assets/cart.png")},
{name: "menu3", src: require("../assets/folder.png")},
{name: "menu4", src: require("../assets/home.png")},
{name: "menu5", src: require("../assets/my.png")},
]
属性及方法一栏
属性名 | 用处 | 默认值 | 是否必须 |
---|---|---|---|
position | 四个方位(LT、LB、RT、RB) | LT | 否 |
menuBg | 菜单背景 | white | 否 |
menuSrc | 菜单图片 | 一个菜单图片 | 否 |
itemBg | 按钮背景 | white | 否 |
width | 按钮宽度 | 50px | 否 |
baseDistance | 位移距离,若item很多,可适当提高 | 150px | 否 |
menuItems | 菜单数组 | 无 | 是 |
方法名 | 用处 | 参数 |
---|---|---|
clickMenu | 点击item触发事件 | item,index |
我的github,求戳,求star
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/54646.html
摘要:前言上一篇面试的总结,大家看的还行,因为量很大,错误在所难免,希望大家发现错误了可以告诉我一声,我的邮箱是,一个小前端的希望。 前言 上一篇面试的总结,大家看的还行,因为量很大,错误在所难免,希望大家发现错误了可以告诉我一声,我的邮箱是236490794@qq.com,一个小前端的希望。showImg(https://segmentfault.com/img/remote/146000...
摘要:用了,这类的框架之后,发现组件化的开发在大部分时间很方便,但是有些时候却用起来很变扭。更新今天发现一个大失误,原来我一直没把包发布到。。。赶紧发布了一下,如果有任务问题,都可以在的里面提出来 用了vue,react这类的框架之后,发现组件化的开发在大部分时间很方便,但是有些时候却用起来很变扭。 比如我需要自定义一个alert组件,组件写起来很方便,但是使用的时候却是这样的: ...
摘要:哥决定把小弟的成果纳入,不只是看上去很美系列,以示鼓励其实还挺有压力的,后浪推前浪,新人赶旧人。连续单击同一站点连续单击同一站点注意不是双击,可以将经过此站点的所有线路突出显示出来。 前言 最近特别忙,承蒙大伙关照,3D机房的项目一个接着一个,领了一帮小弟,搞搞传帮带,乌飞兔走,转眼已经菊黄蟹肥……有个小弟很不错,勤奋好学,很快就把API都摸透了,国庆几天自己折腾着做了个HTML5的魔...
阅读 1426·2019-08-30 15:44
阅读 2199·2019-08-30 11:04
阅读 593·2019-08-29 15:17
阅读 2630·2019-08-26 12:12
阅读 3210·2019-08-23 18:09
阅读 987·2019-08-23 15:37
阅读 1629·2019-08-23 14:43
阅读 3018·2019-08-23 13:13