Vue弹出菜单功能的实现代码


Posted in Javascript onSeptember 12, 2018

言归正传

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

Vue弹出菜单功能的实现代码

组件分析

  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

总结

以上所述是小编给大家介绍的Vue左侧底部弹出菜单功能的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
限制复选框的最大可选数
Jul 01 Javascript
jQuery解决下拉框select设宽度时IE 6/7/8下option超出显示不全
May 27 Javascript
javascript实现base64 md5 sha1 密码加密
Sep 09 Javascript
JavaScript面试开发常用的知识点总结
Aug 08 Javascript
JS 实现Base64编码与解码实例详解
Nov 07 Javascript
详谈javascript精度问题与调整
Jul 08 Javascript
js实现数组内数据的上移和下移的实例
Nov 14 Javascript
vue2.0 移动端实现下拉刷新和上拉加载更多的示例
Apr 23 Javascript
浅析微信扫码登录原理(小结)
Oct 29 Javascript
vue-cli 项目打包完成后运行文件路径报错问题
Jul 19 Javascript
layui输入框中只允许输入整数的实现方法
Sep 18 Javascript
JavaScript 正则应用详解【模式、欲查、反向引用等】
May 13 Javascript
angular4中*ngFor不能对返回来的对象进行循环的解决方法
Sep 12 #Javascript
详解SPA中前端路由基本原理与实现方式
Sep 12 #Javascript
对angular2中的ngfor和ngif指令嵌套实例讲解
Sep 12 #Javascript
vue-cli 使用axios的操作方法及整合axios的多种方法
Sep 12 #Javascript
Vue $emit $refs子父组件间方法的调用实例
Sep 12 #Javascript
bootstrap table表格插件之服务器端分页实例代码
Sep 12 #Javascript
详解html-webpack-plugin插件(用法总结)
Sep 12 #Javascript
You might like
PHP用mysql数据库存储session的代码
2010/03/05 PHP
PHP 面向对象 PHP5 中的常量
2010/05/05 PHP
php下载excel无法打开的解决方法
2013/12/24 PHP
php 过滤英文标点符号及过滤中文标点符号代码
2014/06/12 PHP
PHP中多线程的两个实现方法
2016/10/14 PHP
PHP中功能强大却很少使用的函数实例小结
2016/11/10 PHP
php+ajax实现异步上传文件或图片功能
2017/07/18 PHP
laravel实现图片上传预览,及编辑时可更换图片,并实时变化的例子
2019/11/14 PHP
用javascript实现的支持lrc歌词的播放器
2007/05/17 Javascript
jQuery formValidator表单验证插件开源了 含API帮助、源码、示例
2008/08/14 Javascript
jquery.AutoComplete.js中文修正版(支持firefox)
2010/04/09 Javascript
javascript获取和判断浏览器窗口、屏幕、网页的高度、宽度等
2014/05/08 Javascript
js实现从数组里随机获取元素
2015/01/12 Javascript
javascript省市区三级联动下拉框菜单实例演示
2015/11/29 Javascript
javascript将中国数字格式转换成欧式数字格式的简单实例
2016/08/02 Javascript
bootstrap可编辑下拉框jquery.editable-select
2017/10/12 jQuery
vue.js在标签属性中插入变量参数的方法
2018/03/06 Javascript
vue项目中api接口管理总结
2018/04/20 Javascript
vue树形结构获取键值的方法示例
2018/06/21 Javascript
解决vue 项目引入字体图标报错、不显示等问题
2018/09/01 Javascript
[04:44]DOTA2 2017全国高校联赛视频回顾
2017/08/21 DOTA
整理Python最基本的操作字典的方法
2015/04/24 Python
python实现快速排序的示例(二分法思想)
2018/03/12 Python
Python 旋转打印各种矩形的方法
2019/07/09 Python
Python箱型图绘制与特征值获取过程解析
2019/10/22 Python
python使用itchat模块给心爱的人每天发天气预报
2019/11/25 Python
python GUI库图形界面开发之PyQt5布局控件QHBoxLayout详细使用方法与实例
2020/03/06 Python
基于python实现百度语音识别和图灵对话
2020/11/02 Python
CSS3中的display:grid,网格布局介绍
2019/10/30 HTML / CSS
高山背包:High Sierra
2017/11/23 全球购物
美国美食礼品篮网站:Gourmet Gift Baskets
2019/12/15 全球购物
创建索引时需要注意的事项
2013/05/13 面试题
95%的面试官都会问到的50道Java线程题,附答案
2012/08/03 面试题
教师自我剖析材料范文
2014/09/30 职场文书
机关作风建设剖析材料
2014/10/11 职场文书
总结高并发下Nginx性能如何优化
2021/11/01 Servers