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 相关文章推荐
javascript使用中为什么10..toString()正常而10.toString()出错呢
Jan 11 Javascript
jquery 缓存问题的几个解决方法
Nov 11 Javascript
浅析JavaScript中的同名标识符优先级
Dec 06 Javascript
很全面的JavaScript常用功能汇总集合
Jan 22 Javascript
JavaScript 正则表达式中global模式的特性
Feb 25 Javascript
在Node.js中使用Javascript Generators详解
May 05 Javascript
15位和18位身份证JS校验的简单实例
Jul 18 Javascript
简单实现jquery焦点图
Dec 12 Javascript
Vue框架里使用Swiper的方法示例
Sep 20 Javascript
JavaScript 高性能数组去重的方法
Sep 20 Javascript
详解VUE Element-UI多级菜单动态渲染的组件
Apr 25 Javascript
JS自定义右键菜单实现代码解析
Jul 16 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
MayFish PHP的MVC架构的开发框架
2009/08/13 PHP
Php中用PDO查询Mysql来避免SQL注入风险的方法
2013/04/25 PHP
php批量添加数据与批量更新数据的实现方法
2014/12/16 PHP
PHP递归遍历文件夹去除注释并压缩php源代码的方法示例
2018/05/23 PHP
PHP实现一个轻量级容器的方法
2019/01/28 PHP
显示js对象所有属性和方法的函数
2009/10/16 Javascript
jQuery 跨域访问问题解决方法
2009/12/02 Javascript
我遇到的参数传递中 双引号单引号嵌套问题
2010/02/11 Javascript
jQuery向上遍历DOM树之parents(),parent(),closest()之间的区别
2013/12/02 Javascript
关于JS中prototype的理解
2015/09/07 Javascript
RequireJS多页面应用实例分析
2016/06/29 Javascript
(模仿京东用户注册)用JQuery实现简单表单验证,初学者必看
2018/01/08 jQuery
vue组件编写之todolist组件实例详解
2018/01/22 Javascript
如何在js代码中消灭for循环实例详解
2018/07/29 Javascript
vue计算属性computed、事件、监听器watch的使用讲解
2019/01/21 Javascript
layui表格设计以及数据初始化详解
2019/10/26 Javascript
JavaScript中的this妙用实例分析
2020/05/09 Javascript
python使用心得之获得github代码库列表
2014/06/25 Python
决策树的python实现方法
2014/11/18 Python
详解Django中Request对象的相关用法
2015/07/17 Python
Python实现的json文件读取及中文乱码显示问题解决方法
2018/08/06 Python
Python异常处理操作实例详解
2018/08/28 Python
Docker部署Python爬虫项目的方法步骤
2020/01/19 Python
Python 实现将numpy中的nan和inf,nan替换成对应的均值
2020/06/08 Python
Python实现寻找回文数字过程解析
2020/06/09 Python
Django Form设置文本框为readonly操作
2020/07/03 Python
matplotlib subplot绘制多个子图的方法示例
2020/07/28 Python
python 使用elasticsearch 实现翻页的三种方式
2020/07/31 Python
html5唤醒APP小记
2019/03/27 HTML / CSS
LookFantastic丹麦:英国美容护肤精品在线商城
2016/08/18 全球购物
会计专业自我鉴定范文
2013/12/29 职场文书
2015教师年度考核评语
2015/03/25 职场文书
《海上日出》教学反思
2016/02/23 职场文书
导游词之无锡梅园
2019/11/28 职场文书
CSS 制作波浪效果的思路
2021/05/18 HTML / CSS
直播实况, OMG破敌三路五十分钟大战神技局摩托车
2022/04/01 DOTA