前言

上一篇面试的总结,大家看的还行,因为量很大,错误在所难免,希望大家发现错误了可以告诉我一声,我的邮箱是236490794@qq.com,一个小前端的希望。

言归正传

我们老样子直接先上效果图再开始今天的分享
这个项目的github可以看一看

组件分析

  1. 界面组成
  2. 逻辑分析
  3. 最终实现
界面组成

从上图中,我们可以看出界面主要分为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我简单的带过一下

<div>
<div class="menu_container" ref="menuHome" @click="toggleMenu">
<img :src="menuSrc"><!--menu图-->
</div>
<div class="menu_item" v-for="(item,index) in menuItems" :id="item.name" @click="clickMenu(item,index)">
<img :src="item.src"><!--item图-->
</div>
</div>

核心实现
通过分析可以得出,每个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')},
]
<toggle-menu :menuItems="menuItems"
@clickMenu="clickMenu"
></toggle-menu>

属性及方法一栏

属性名 用处 默认值 是否必须
position 四个方位(LT、LB、RT、RB) LT
menuBg 菜单背景 white
menuSrc 菜单图片 一个菜单图片
itemBg 按钮背景 white
width 按钮宽度 50px
baseDistance 位移距离,若item很多,可适当提高 150px
menuItems 菜单数组
方法名 用处 参数
clickMenu 点击item触发事件 item,index

好了,差不多就分享这么多,


我的github,求戳,求star

弹弹弹,弹走鱼尾纹的弹出菜单(vue)的更多相关文章

  1. Web标准:四、纵向导航菜单及二级弹出菜单

    Web标准:四.纵向导航菜单及二级弹出菜单 知识点: 1.纵向列表 2.标签的默认样式 3.css派生选择器 4.css选择器的分组 5.纵向二级列表 6.相对定位和绝对定位   1)纵向列表 可以看 ...

  2. dragView 屏幕拖拽并且弹出菜单的控件

    dragView 因项目新需求需要添加一个屏幕拖拽按钮可以弹出菜单的控件,因为不是我做的闲来无事写一个demo吧 可能存在一些小bug(毕竟就写了几个小时)兄弟姐妹们理解思路就行 具体的可以自己调试一 ...

  3. 向上弹出菜单jQuery插件

    插件名:柯乐义英文名:Keleyijs文件名称:jquery.keleyi.js插件功能:该插件可以让你轻易地在页面上构建一个向上弹出的二级菜单. 示例查看:http://keleyi.com/kel ...

  4. html5手机端遮罩弹出菜单代码

    效果体验:http://hovertree.com/texiao/html5/17/ 效果图: 代码如下: <!doctype html> <html lang="zh&q ...

  5. DIV+CSS制作二级横向弹出菜单,略简单

    没有使用JavaScript控制二级菜单的显示,结果如上图所示. 代码如下: <!DOCTYPE html> <html> <head> <meta char ...

  6. vc++ 如何添加右键弹出菜单

    一.创建新工程 二.编辑菜单资源 1.添加菜单 按"Ctrl+R",双击"Menu"图标 2.于菜单编辑器内编辑菜单 四.添加代码(红色部分) void CCM ...

  7. 创建 iPhone/iOS8 弹出菜单(窗口)

    基本步骤 添加视图:主视图与弹出视图 关联视图 配置弹出视图 编码实现:弹出菜单样式及控制器委托 override func prepareForSegue(segue: UIStoryboardSe ...

  8. android 单选、多选弹出菜单

    菜单单选窗口: import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInte ...

  9. [Flex] PopUpButton系列 —— 弹出菜单的行高设置

    <?xml version="1.0" encoding="utf-8"?> <!--Flex中如何通过variableRowHeight样式 ...

随机推荐

  1. windows vs2015 编译openssl 1.1.0c

    1,到openssl官网下载源码. 2,安装activePerl,我放在网盘:https://pan.baidu.com/s/1ZHe24yRcPtIuSiEa-3oqxw 3.安装完毕后,使用 VS ...

  2. java:异常机制(try,catch,finally,throw,throws,自定义异常)

    * String类中的格式化字符串的方法: * public static String format(String format, Object... args):使用指定的格式字符串和参数返回一个 ...

  3. opencv的曲线拟合polyfit

    推荐一个不错的网页,可以直接用solve函数求解方程组: http://m.blog.csdn.net/u014652390/article/details/52789591 4.1 曲线拟合的最小二 ...

  4. c++ 指针(二)

    指针 (4)指针数组 #include <iostream> using namespace std; ; int main () { , , }; ; i < MAX; i++) ...

  5. Mybatis 之 SQL生成技巧

    一.增 1.<trim> 和<if>实现数据插入 <insert id="addInOrder" parameterType="XXX.mo ...

  6. 【转】应用宝基于Robotium自动化测试

    (转载:http://tmq.qq.com/2016/05/robotium_for_app_test/) 1 背景目的应用宝项目组采用FT(Feature Team)模式,整个项目组分为多个FT,而 ...

  7. 【转】mysql的group_concat函数,默认最大长度是1024

    mysql的group_concat函数,默认最大长度是1024 查询sql: show variables like 'group_concat_max_len'; 设置方式: 修改配置文件my.i ...

  8. 项目中使用vue的API。 和项目的结构

    <template> <!--组件的 结构--> <div id="app"> <h3>{{ msg }}</h3> & ...

  9. 浅谈React工作原理

    浅谈React工作原理:https://www.cnblogs.com/yikuu/p/9660932.html 转自:https://cloud.tencent.com/info/63f656e0b ...

  10. Linux 释放占用端口

    在使用 Swoole 扩展库的 WebSocket 服务时,直接退出终端,但是 WebSocket 使用的端口依然坚挺的在被占用着. 导致再次启动 WebSocket 服务失败. 具体操作: 1.ne ...