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 相关文章推荐
Add a Formatted Table to a Word Document
Jun 15 Javascript
javascript查找字符串中出现最多的字符和次数的小例子
Oct 29 Javascript
jquery选择符快速提取web表单数据示例
Mar 27 Javascript
Js为表单动态添加节点内容的方法
Feb 10 Javascript
JavaScript实现邮箱地址自动匹配功能代码
Nov 28 Javascript
js自定义QQ菜单效果
Jan 10 Javascript
jQuery实现的动态文字变化输出效果示例【附演示与demo源码下载】
Mar 24 jQuery
echarts鼠标覆盖高亮显示节点及关系名称详解
Mar 17 Javascript
去掉vue 中的代码规范检测两种方法(Eslint验证)
Mar 21 Javascript
vue的token刷新处理的方法
Jul 17 Javascript
vue video和vue-video-player实现视频铺满教程
Oct 30 Javascript
JavaScript实现复选框全选和取消全选
Nov 20 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 在5.1.* 和5.2.*之间 PDO数据库操作中的不同之处小结
2012/03/07 PHP
解析在zend Farmework下如何创立一个FORM表单
2013/06/28 PHP
PHP生成自适应大小的缩略图类及使用方法分享
2014/05/06 PHP
php中smarty变量修饰用法实例分析
2015/06/11 PHP
PHP中两个float(浮点数)比较实例分析
2015/09/27 PHP
php使用pear_smtp发送邮件
2016/04/15 PHP
万能的php分页类
2017/07/06 PHP
thinkPHP5框架实现基于ajax的分页功能示例
2018/06/12 PHP
laravel 使用事件系统统计浏览量的实现
2019/10/16 PHP
PHP的图像处理实例小结【文字水印、图片水印、压缩图像等】
2019/12/20 PHP
Js 本页面传值实现代码
2009/05/17 Javascript
ExtJS4如何给同一个formpanel不同的url
2014/05/02 Javascript
js去除输入框中所有的空格和禁止输入空格的方法
2014/06/09 Javascript
浅谈angularJS 作用域
2015/07/05 Javascript
深入理解JQuery中的事件与动画
2016/05/18 Javascript
浅谈js图片前端预览之filereader和window.URL.createObjectURL
2016/06/30 Javascript
阿里云ecs服务器中安装部署node.js的步骤
2016/10/08 Javascript
原生JS实现九宫格抽奖效果
2017/04/01 Javascript
React操作真实DOM实现动态吸底部的示例
2017/10/23 Javascript
layui 表格的属性的显示转换方法
2018/08/14 Javascript
Nodejs实现用户注册功能
2019/04/14 NodeJs
Js逆向实现滑动验证码图片还原的示例代码
2020/03/10 Javascript
[44:26]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#4EG VS Fnatic第二局
2016/03/03 DOTA
[01:56]生活中的妖精之七夕特别档
2016/08/09 DOTA
[05:09]2016国际邀请赛中国区预选赛淘汰赛首日精彩回顾
2016/06/29 DOTA
[52:07]完美世界DOTA2联赛PWL S3 LBZS vs access 第二场 12.10
2020/12/13 DOTA
用Python的Django框架完成视频处理任务的教程
2015/04/02 Python
HTML中使用python屏蔽一些基本功能的方法
2017/07/07 Python
django DRF图片路径问题的解决方法
2018/09/10 Python
两个元祖T1=('a', 'b'),T2=('c', 'd')使用匿名函数将其转变成[{'a': 'c'},{'b': 'd'}]的几种方法
2019/03/05 Python
类、抽象类、接口的差异
2016/06/13 面试题
生物科学专业自荐书
2014/06/20 职场文书
2014年社区综治工作总结
2014/11/17 职场文书
民事起诉书范本
2015/05/19 职场文书
python中出现invalid syntax报错的几种原因分析
2022/02/12 Python
mysql insert 存在即不插入语法说明
2022/03/25 MySQL