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 相关文章推荐
js正确获取元素样式详解
Aug 07 Javascript
JQuery 学习笔记01 JQuery初接触
May 06 Javascript
JavaScript高级程序设计 阅读笔记(十八) js跨平台的事件
Aug 14 Javascript
IE6下opacity与JQuery的奇妙结合
Mar 01 Javascript
dwz 如何去掉ajaxloading具体代码
May 22 Javascript
jQuery基于cookie实现的购物车实例分析
Dec 24 Javascript
基于jQuery实现滚动刷新效果
Jan 09 Javascript
一道面试题引发的对javascript类型转换的思考
Mar 06 Javascript
react.js 获取真实的DOM节点实例(必看)
Apr 17 Javascript
vue-cli初始化项目中使用less的方法
Aug 09 Javascript
详解webpack 热更新优化
Sep 13 Javascript
如何解决jQuery 和其他JS库的冲突
Jun 22 jQuery
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 程序员也要学会使用“异常”
2009/06/16 PHP
ThinkPHP应用模式扩展详解
2014/07/16 PHP
Yii框架form表单用法实例
2014/12/04 PHP
PHP 序列化和反序列化函数实例详解
2020/07/18 PHP
php关联数组与索引数组及其显示方法
2018/03/12 PHP
laravel7学习之无限级分类的最新实现方法
2020/09/30 PHP
网页开发中的容易忽略的问题 javascript HTML中的table
2009/04/15 Javascript
JS+CSS实现电子商务网站导航模板效果代码
2015/09/10 Javascript
JQuery 设置checkbox值二次无效的解决方法
2016/07/22 Javascript
js断点调试经验分享
2017/12/08 Javascript
从parcel.js打包出错到选择nvm的全部过程
2018/01/23 Javascript
微信、QQ、微博、Safari中使用js唤起App
2018/01/24 Javascript
nodeJs实现基于连接池连接mysql的方法示例
2018/02/10 NodeJs
详解vue填坑之解决部分浏览器不支持pushState方法
2018/07/12 Javascript
Vue.js的动态组件模板的实现
2018/11/26 Javascript
超轻量级的js时间库miment使用解析
2019/08/02 Javascript
pyside写ui界面入门示例
2014/01/22 Python
Python自动化运维和部署项目工具Fabric使用实例
2016/09/18 Python
Django 对IP访问频率进行限制的例子
2019/08/30 Python
Python 中list ,set,dict的大规模查找效率对比详解
2019/10/11 Python
使用python绘制温度变化雷达图
2019/10/18 Python
python实现对列表中的元素进行倒序打印
2019/11/23 Python
解决windows下python3使用multiprocessing.Pool出现的问题
2020/04/08 Python
Scrapy+Selenium自动获取cookie爬取网易云音乐个人喜爱歌单
2021/02/01 Python
Django如何重置migration的几种情景
2021/02/24 Python
使用layui实现左侧菜单栏及动态操作tab项的方法
2020/11/10 HTML / CSS
家得宝加拿大家装网上商店:The Home Depot加拿大
2016/08/27 全球购物
卡西欧G-SHOCK英国官网: 防水防震手表
2018/01/08 全球购物
计算机大学生的自我评价
2013/10/15 职场文书
珍珠奶茶店创业计划书
2014/01/11 职场文书
学校端午节活动方案
2014/08/23 职场文书
党员干部观看《周恩来四个昼夜》思想汇报
2014/09/10 职场文书
2015年度环卫处工作总结
2015/07/24 职场文书
golang interface判断为空nil的实现代码
2021/04/24 Golang
vue里使用create, mounted调用方法
2022/04/26 Vue.js
canvas 中如何实现物体的框选
2022/08/05 Javascript