微信小程序开发之圆形菜单 仿建行圆形菜单实例


Posted in Javascript onDecember 12, 2016

建行APP首页有个圆形菜单.仿了个玩具出来.  

微信小程序开发之圆形菜单 仿建行圆形菜单实例

功能介绍:

1.一个圆形背景.六个item菜单.中间是微信用户的头像;

2.触摸滚动.速度较小时,随手指滚动,手指抬起,滚动停止;速度较大时,随手指滚动,手指抬起,还会自动滚动一段时间;

上一张真机截图:

微信小程序开发之圆形菜单 仿建行圆形菜单实例

上代码:

1.index.js

var app = getApp()
Page({
 data: {
  userInfo: {},
  menuList: {},//菜单集合
  animationData: {},
  startPoint: {},//触摸开始
  dotPoint: {},//圆点坐标
  startAngle: 0,//开始角度
  tempAngle: 0,//移动角度
  downTime: 0,//按下时间
  upTime: 0,//抬起时间
  // isRunning: false,//正在滚动
 },
 onLoad: function () {
  var that = this
  //调用应用实例的方法获取全局数据
  app.getUserInfo(function (userInfo) {
   //更新数据
   that.setData({
    userInfo: userInfo,
   })
  })
  wx.getSystemInfo({
   success: function (res) {
    var windowWidth = res.windowWidth * 0.5;
    that.setData({
     //圆点坐标,x为屏幕一半,y为半径与margin-top之和,px
     //后面获取的触摸坐标是px,所以这里直接用px.
     dotPoint: { clientX: windowWidth, clientY: 250 }
    })
   }
  })
 },
 onReady: function (e) {
  var that = this;
  app.menuConfig = {
   menu: [
    { 'index': 0, 'menu': '我的账户', 'src': '../images/account.png' },
    { 'index': 1, 'menu': '信用卡', 'src': '../images/card.png' },
    { 'index': 2, 'menu': '投资理财', 'src': '../images/investment.png' },
    { 'index': 3, 'menu': '现金贷款', 'src': '../images/loan.png' },
    { 'index': 4, 'menu': '特色服务', 'src': '../images/service.png' },
    { 'index': 5, 'menu': '转账汇款', 'src': '../images/transfer.png' }
   ]
  }
  // 绘制转盘
  var menuConfig = app.menuConfig.menu,
   len = menuConfig.length,
   menuList = [],
   degNum = 360 / len // 文字旋转 turn 值
  for (var i = 0; i < len; i++) {
   menuList.push({ deg: i * degNum, menu: menuConfig[i].menu, src: menuConfig[i].src });
   console.log("menu:" + menuConfig[i].menu)
  }
  that.setData({
   menuList: menuList
  });
 },
 // 菜单拖动的三个方法
 buttonStart: function (e) {
  this.setData({
   startPoint: e.touches[0]
  })
  var x = this.data.startPoint.clientX - this.data.dotPoint.clientX;
  var y = this.data.startPoint.clientY - this.data.dotPoint.clientY;
  var startAngle = Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
  this.setData({
   startAngle: startAngle
  })

 },
 buttonMove: function (e) {
  //获取滑动时的时间
  var downTime = Date.now();
  this.setData({
   downTime: downTime
  })
  var that = this;
  var endPoint = e.touches[e.touches.length - 1]
  //根据触摸位置计算角度
  var x = endPoint.clientX - this.data.dotPoint.clientX;
  var y = endPoint.clientY - this.data.dotPoint.clientY;
  var moveAngle = Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI
  var quadrant = 1;
  if (x >= 0) {
   quadrant = y >= 0 ? 4 : 1;
  } else {
   quadrant = y >= 0 ? 3 : 2;
  }
  var tempAngle = 0;
  // 如果是一、四象限,则直接end角度-start角度,角度值都是正值 
  if (quadrant == 1 || quadrant == 4) {
   tempAngle += moveAngle - this.data.startAngle;
  } else
  // 二、三象限,色角度值是负值 
  {
   tempAngle += this.data.startAngle - moveAngle;
  }
  var menuConfig = app.menuConfig.menu;
  var menuList = [];
  for (var i = 0; i < this.data.menuList.length; i++) {
   menuList.push({ deg: this.data.menuList[i].deg + tempAngle, menu: menuConfig[i].menu, src: menuConfig[i].src });
  }
  this.setData({
   menuList: menuList
  })
  //重置开始角度
  this.setData({
   startPoint: e.touches[e.touches.length - 1]
  })
  var endX = this.data.startPoint.clientX - this.data.dotPoint.clientX;
  var endY = this.data.startPoint.clientY - this.data.dotPoint.clientY;
  var startAngle = Math.asin(endY / Math.hypot(endX, endY)) * 180 / Math.PI;
  this.setData({
   startAngle: startAngle,
   tempAngle: tempAngle
  })
 },
 buttonEnd: function (e) {
  // 计算,每秒移动的角度 
  var that = this;
  var upTime = Date.now();
  var angleSpeed = this.data.tempAngle * 1000 / (upTime - this.data.downTime);
  if (Math.abs(angleSpeed) < 100) {
   //速度小于100时,停止滚动
   return
  } else {
   //速度大于100时,自动滚动
   if (angleSpeed > 0) {
    if (angleSpeed > 500) angleSpeed = 500
    var animationRun = wx.createAnimation({
     duration: 2000,
     //ease-out结束时减速
     timingFunction: 'ease-out'
    })
    that.animationRun = animationRun
    animationRun.rotate(angleSpeed).step()
    that.setData({
     animationData: animationRun.export(),
    })
   }
   else {
    if (angleSpeed < -500) angleSpeed = -500
    angleSpeed = Math.abs(angleSpeed);
    var animationRun = wx.createAnimation({
     duration: 2000,
     // ease-out结束时减速
     timingFunction: 'ease-out'
    })
    that.animationRun = animationRun
    animationRun.rotate(-angleSpeed).step()
    that.setData({
     animationData: animationRun.export(),
    })
   }
  }
 }
})

2.index.wxml

<view class="circle-out">
 <view class="circle-in">
  <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}"></image>
  <view class="menu-list" catchtouchmove="buttonMove" catchtouchstart="buttonStart" catchtouchend="buttonEnd">
   <view class="menu-item" wx:for="{{menuList}}" wx:key="unique" animation="{{animationData}}">
    <view class="menu-circle-item" style="-webkit-transform: rotate({{item.deg}}deg);" data-menu="{{item.menu}}">
     <image class="image-style" src="{{item.src}}"></image>
    </view>
    <view class="menu-circle-text-item" style="-webkit-transform: rotate({{item.deg}}deg);">
     <text class="text-style">{{item.menu}}</text>
    </view>
   </view>
  </view>
 </view>
</view>

3.index.wxss

page {
 background-image: url('http://ac-ejx0nsfy.clouddn.com/ac767407f474e1c3970a.jpg');
 background-attachment: fixed;
 background-repeat: no-repeat;
 background-size: cover;
}

.circle-out {
 margin: 75px auto;
 position: relative;
 width: 350px;
 height: 350px;
 border-radius: 50%;
 background-color: #415cab;
}

.userinfo-avatar {
 width: 70px;
 height: 70px;
 border-radius: 50%;
 position: absolute;
 top: 0;
 bottom: 0;
 left: 0;
 right: 0;
 margin: auto;
}

/**子控件的透明度等于父控件透明度*子控件透明度,父控件的opacity设置后,
所以子控件opacity设置为1依然无效,必须分离开
*/

.circle-in {
 position: absolute;
 width: 330px;
 height: 330px;
 border-radius: 50%;
 top: 0;
 bottom: 0;
 left: 0;
 right: 0;
 margin: auto;
 background-color: #fff;
}

/**菜单*/

.menu-list {
 position: absolute;
 left: 0;
 top: 0;
 width: inherit;
 height: inherit;
}

.menu-item {
 position: absolute;
 left: 0;
 top: 0;
 width: 100%;
 height: 100%;
 font-weight: 500;
}

.menu-circle-item {
 -webkit-transform-origin: 50% 150px;
 transform-origin: 50% 150px;
 margin: 0 auto;
 margin-top: 15px;
 position: relative;
 height: 50px;
 width: 50px;
 background-color: #77c2fc;
 text-align: center;
 border-radius: 50%;
}

.image-style {
 height: 25px;
 width: 25px;
 color: #f00;
 margin: 12.5px auto;
}

.text-style {
 margin: 5px auto;
 font-size: 15px;
}

/***/

.menu-circle-text-item {
 -webkit-transform-origin: 50% 100px;
 transform-origin: 50% 100px;
 margin: 0 auto;
 position: relative;
 height: 25px;
 width: auto;
 text-align: center;
}

js注释补充:

获取手指抬起时的角速度

微信小程序开发之圆形菜单 仿建行圆形菜单实例

1.获取角度.借图说话.

Math.sqrt( x * x + y * y )是斜边长,乘以 sin a 就是 y 的长度;

获取a的角度:Math.asin(y / Math.hypot(x, y) ;

[ hypot是x * x + y * y ]

2.根据角度差计算角速度

var angleSpeed = this.data.tempAngle * 1000 / (upTime - this.data.downTime);

3.当角速度小于100的时候触摸滑动停止,不自动滚动;大于100时,自动滚动.我这里用动画,有个问题:很难把握动画持续时间和速度的关系.总感觉不够流畅.我表示不能忍.

4.分象限的问题.看看代码就知道了.主要是根据up时的触摸点相对于圆点的X轴差值来计算.大于0就是一四象限.小于0就是二三象限.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Jquery CheckBox全选方法代码附js checkbox全选反选代码
Jun 09 Javascript
js获得页面的高度和宽度的方法
Feb 23 Javascript
angularjs学习笔记之双向数据绑定
Sep 26 Javascript
基于JavaScript实现跳转提示页面
Sep 24 Javascript
JS实现Ajax的方法分析
Dec 20 Javascript
EsLint入门学习教程
Feb 17 Javascript
纯js实现画一棵树的示例
Sep 05 Javascript
jQuery使用zTree插件实现可拖拽的树示例
Sep 23 jQuery
VUE饿了么树形控件添加增删改功能的示例代码
Oct 17 Javascript
微信小程序多音频播放进度条问题
Aug 28 Javascript
require.js 加载过程与使用方法介绍
Oct 30 Javascript
vue elementui 实现搜索栏公共组件封装的实例代码
Jan 20 Javascript
深入理解javascript中concat方法
Dec 12 #Javascript
js仿微信语音播放实现思路
Dec 12 #Javascript
解析JavaScript数组方法reduce
Dec 12 #Javascript
实例分析浏览器中“JavaScript解析器”的工作原理
Dec 12 #Javascript
JS双击变input框批量修改内容
Dec 12 #Javascript
jQuery中animate的几种用法与注意事项
Dec 12 #Javascript
Websocket协议详解及简单实例代码
Dec 12 #Javascript
You might like
PHP安装攻略:常见问题解答(二)
2006/10/09 PHP
关于Intype一些小问题的解决办法
2008/03/28 PHP
PHP 采集程序原理分析篇
2010/03/05 PHP
PHP中开发XML应用程序之基础篇 添加节点 删除节点 查询节点 查询节
2010/07/09 PHP
PHP实现获取图片颜色值的方法
2014/07/11 PHP
使用php方法curl抓取AJAX异步内容思路分析及代码分享
2014/08/25 PHP
使用symfony命令创建项目的方法
2016/03/17 PHP
PHP中phar包的使用教程
2017/06/14 PHP
yii2.0整合阿里云oss的示例代码
2017/09/19 PHP
JavaScript国旗变换效果代码
2008/08/13 Javascript
javascript 当前日期转化为中文的实现代码
2010/05/13 Javascript
js跨域请求的5中解决方式
2015/07/02 Javascript
jQuery学习心得总结(必看篇)
2016/06/10 Javascript
jQuery AJAX timeout 超时问题详解
2016/06/21 Javascript
详解Vue爬坑之vuex初识
2017/06/14 Javascript
Vue.js 中的 v-model 指令及绑定表单元素的方法
2018/12/03 Javascript
JavaScript对象的特性与实践应用深入详解
2018/12/30 Javascript
Vue渲染过程浅析
2019/03/14 Javascript
基于Vue+ElementUI的省市区地址选择通用组件
2019/11/20 Javascript
[48:38]DOTA2亚洲邀请赛 3.31 小组赛 B组 Mineski vs Secret
2018/03/31 DOTA
13个最常用的Python深度学习库介绍
2017/10/28 Python
pandas 两列时间相减换算为秒的方法
2018/04/20 Python
python matplotlib实现双Y轴的实例
2019/02/12 Python
几个适合python初学者的简单小程序,看完受益匪浅!(推荐)
2019/04/16 Python
python 实现创建文件夹和创建日志文件的方法
2019/07/07 Python
python怎么判断模块安装完成
2020/06/19 Python
Django中Q查询及Q()对象 F查询及F()对象用法
2020/07/09 Python
解决Python 函数声明先后顺序出现的问题
2020/09/02 Python
利用CSS3实现进度条的两种姿势详解
2017/03/21 HTML / CSS
美国最便宜的旅游网站:CheapTickets
2017/07/09 全球购物
贺卡寄语大全
2014/04/11 职场文书
质量整改报告范文
2014/11/08 职场文书
Python机器学习算法之决策树算法的实现与优缺点
2021/05/13 Python
MySQL优化之如何写出高质量sql语句
2021/05/17 MySQL
实体类或对象序列化时,忽略为空属性的操作
2021/06/30 Java/Android
解决MultipartFile.transferTo(dest) 报FileNotFoundExcep的问题
2021/07/01 Java/Android