一入前端深似海,从此红尘是路人系列第十二弹之移动端模拟IOS虚拟按钮效果

简介: 用过苹果的大家都知道,苹果公司做了一个虚拟按钮,让页面上的挂件可被拖拽并吸附到屏幕边框处,降低挂件对用户的干扰。该效果如果用JavaScript进行实现又该如何实现呢,接下来我将分享给大家。首先上一张效果图

用过苹果的大家都知道,苹果公司做了一个虚拟按钮,让页面上的挂件可被拖拽并吸附到屏幕边框处,降低挂件对用户的干扰。该效果如果用JavaScript进行实现又该如何实现呢,接下来我将分享给大家。首先上一张效果图


 

一、思路来源

首先体验过该虚拟按钮的都知道,它是根据距离屏幕边距进行一个位移判断的。当手从屏幕中放开的时候,对边距判断后进行动态效果操纵,这里动态我们将用到transform进行控制,代码也是纯原生JavaScript。这里我们也只是做一个移动效果的模拟,对于其中的一些功能并没有添加进来。

二、代码编写

1、html


<div class="i-pendant" id="pendant">
  <div class="drag"></div>
</div>

2、css


.i-pendant {
  width: 60px;
  height: 60px;
  border-radius: 5px;
  background: #999;
  position: fixed;
  top: 300px;
  right: 0;
  z-index: 90;
  -webkit-transform: translate3d(0, 0, 0);
          transform: translate3d(0, 0, 0);
  -webkit-transition-property: -webkit-transform;
  transition-property: -webkit-transform;
  transition-property: transform;
  transition-property: transform, -webkit-transform;
  -webkit-transition-delay: 0s;
          transition-delay: 0s;
  -webkit-transition-timing-function: ease-out;
          transition-timing-function: ease-out;
}
.drag {
  width: 80%;
  height: 80%;
  margin: 10%;
  border-radius: 100%;
  background: #fff;
}

3、JavaScript

首先我们需要先获取虚拟按钮,并定义一些全局状态,方便之后的拖拽判定


var pendant = document.getElementById("pendant");
var posX = parseInt(pendant.offsetLeft);
var posY = parseInt(pendant.offsetTop);
var screenWidth = document.documentElement.clientWidth;
var screenHeight = document.documentElement.clientHeight;

// 判断手势按下状态
var state = {
  type: null
};

//检测是否move事件
var isMove = false;

定义不同手势对应的事件


var Events = {
  // 手势按下
  onmousedown: function (event) {},
  // 手势抬起
  onmouseup: function (event) {},
  // 手势移动
  onmousemove: function (event) {}
};

接下来我们需要做的就是一一实现这些手势事件,手势按下事件实现:


// 手势按下
onmousedown: function (event) {
  state.type = 'down';

  screenWidth = document.documentElement.clientWidth;
  screenHeight = document.documentElement.clientHeight;

  var _touchs = event.targetTouches[0];
  posX = _touchs.clientX;
  posY = _touchs.clientY;

  isMove = false;
}

手势抬起事件实现:


// 手势抬起
onmouseup: function (event) {

  if (isMove) {
    var _top = posY,
      _left = posX;

    state.type = 'up';

    if ((posY + parseInt(pendant.clientHeight) / 2) <= (screenHeight / 2)) {
      //在上半部分
      if ((posX + parseInt(pendant.clientWidth) / 2) <= (screenWidth / 2)) {
        //在左半部分
        if ((posY + parseInt(pendant.clientHeight) / 2) <= (posX + parseInt(pendant.clientWidth) / 2)) {
          //靠近上方
          _top = 0;
        } else {
          //靠近左边
          _left = 0;
        }
      } else {
        //在右半部分
        if ((posY + parseInt(pendant.clientHeight) / 2) <= (screenWidth - (posX + parseInt(pendant.clientWidth) / 2))) {
          //靠近上方
          _top = 0;
        } else {
          //靠近右边
          _left = (screenWidth - parseInt(pendant.clientWidth));
        }
      }
    } else {
      //下半部分
      if ((posX + parseInt(pendant.clientWidth) / 2) <= (screenWidth / 2)) {
        //在左半部分
        if ((screenHeight - (posY + parseInt(pendant.clientHeight) / 2)) <= (posX + parseInt(pendant.clientWidth) / 2)) {
          //靠近下方
          _top = (screenHeight - parseInt(pendant.clientHeight));
        } else {
          //靠近左边
          _left = 0;
        }
      } else {//在右半部分
        if ((screenHeight - (posY + parseInt(pendant.clientHeight) / 2)) <= (screenWidth - (posX + parseInt(pendant.clientWidth) / 2))) {
          //靠近上方
          _top = (screenHeight - parseInt(pendant.clientHeight));
        } else {
          //靠近右边
          _left = (screenWidth - parseInt(pendant.clientWidth));
        }
      }
    }
    setTransform(_left, _top);
  } else {
    if (!!event) {
      //点击事件触发入口
      console.log('touch event');
    }
  }
}

手势移动事件实现:


// 手势移动
onmousemove: function (event) {
  isMove = true;

  // 如果这个元素的位置内只有一个手指的话
  var _top = posY,
    _left = posX;

  state.type = 'move';

  if (event.targetTouches.length === 1) {
    event.preventDefault();// 阻止浏览器默认事件,重要
    var touch = event.targetTouches[0];
    if ((touch.clientY) <= 0) {
      //超过顶部
      _top = 0;

    } else if (touch.clientY > (screenHeight - parseInt(pendant.clientHeight))) {//超过底部
      _top = screenHeight - parseInt(pendant.clientHeight);

    } else {
      _top = touch.clientY - parseInt(pendant.clientHeight) / 2;

    }

    if (touch.clientX <= 0) {
      //超过左边
      _left = 0;

    } else if (touch.clientX > (screenWidth - parseInt(pendant.clientWidth))) {
      //超过右边
      _left = screenWidth - parseInt(pendant.clientWidth);

    } else {
      _left = touch.clientX - parseInt(pendant.clientWidth) / 2;

    }

    setTransform(_left, _top);

  }
}

我们在手势事件中可以看到一个函数叫setTransform,接下来我们将实现它:


/**
 * @param {[type]} _left [左偏移]
 * @param {[type]} _top  [顶部偏移]
 */
function setTransform(_left, _top) {
  posX = _left;
  posY = _top;

  if (state.type === 'up') {
    pendant.style.webkitTransitionDuration = '.2s';
  } else {
    pendant.style.webkitTransitionDuration = '0s';
  }
  pendant.style.webkitTransform = 'translate3d(' + posX + 'px,' + posY + 'px,0)';
}

最后我们还需要对虚拟按钮进行一个参数的初始化


//初始化虚拟按钮参数
function init() {
  screenWidth = document.documentElement.clientWidth;
  screenHeight = document.documentElement.clientHeight;

  var _top = posY,
    _left = posX;

  if ((posY + parseInt(pendant.clientHeight)) > screenHeight) {
    //窗口改变适应超出的部分
    _top = (screenHeight - parseInt(pendant.clientHeight));
  }
  if ((posX + parseInt(pendant.clientWidth)) > screenWidth) {
    //窗口改变适应超出的部分
    _left = (screenWidth - parseInt(pendant.clientWidth));
  }

  //把样式的top、left赋值到transform去
  setTransform(_left, _top);

  pendant.style.top = 0;
  pendant.style.left = 0;

  state.type = 'init';

  Events.onmouseup(null);
}

最后我们调用一下init方法,虚拟按钮拖动效果就模拟出来了。小伙伴还不赶紧去试一下看看,是不是和苹果的虚拟按钮拖动起来是一样的效果呢。如果觉得好用或者好玩的话,记得给qiangdada点个赞哦↖(^ω^)↗




原文发布时间为:2017年01月18日
原文作者: qiangdada

本文来源:开源中国 如需转载请联系原作者




目录
相关文章
|
1月前
|
JavaScript 前端开发
vue前端下载,实现点击按钮弹出本地窗口,选择自定义保存路径
这个不用代码实现(网上也找不到方法可以调出另存为窗口),更改浏览器设置就可以,否则,现在的浏览器都是默认直接保存到下载路径中
61 3
|
3月前
|
移动开发 编解码 前端开发
【面试题】前端 移动端自适应?
【面试题】前端 移动端自适应?
|
4月前
|
前端开发 JavaScript
Web前端之移动端课程开发之06.bootstrap
Web前端之移动端课程开发之06.bootstrap
46 0
|
7月前
|
iOS开发
iOS MFMessageComposeViewController不显示取消按钮,导航条上白色,无取消按钮,无法返回应用...
iOS MFMessageComposeViewController不显示取消按钮,导航条上白色,无取消按钮,无法返回应用...
28 0
|
7月前
|
JSON 前端开发 JavaScript
前端(十七)——gitee上开源一个移动端礼盒商城项目(前端+后台)
前端(十七)——gitee上开源一个移动端礼盒商城项目(前端+后台)
|
1月前
|
Web App开发 前端开发 网络安全
前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
【2月更文挑战第21天】前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
50 1
前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
|
1月前
|
前端开发 JavaScript 容器
前端vw自适应解决方案,适用pc端以及移动端,适用webpack以及vite,适用vue以及react
前端vw自适应解决方案,适用pc端以及移动端,适用webpack以及vite,适用vue以及react
66 0
|
1月前
|
编解码 前端开发 UED
Web前端开发中的移动端适配与响应式设计
【2月更文挑战第11天】 对于现代 Web 前端开发而言,移动端适配与响应式设计是至关重要的技术环节。移动设备的普及使得用户更多地通过手机或平板设备访问网站,因此,如何有效地适配各种屏幕尺寸并提供良好的用户体验成为了前端开发者需要面对的重要问题。本文将介绍移动端适配与响应式设计的基本原理,并结合实际案例探讨其在前端开发中的应用。
|
3月前
|
iOS开发
你知道IOS移动端到操作手势有哪些吗?
你知道IOS移动端到操作手势有哪些吗?
|
4月前
|
移动开发 前端开发 JavaScript
web前端移动端课程之canvas教程系列
web前端移动端课程之canvas教程系列
48 0