一入前端深似海,从此红尘是路人系列第十二弹之移动端模拟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

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




目录
相关文章
|
6月前
|
JavaScript 前端开发
vue前端下载,实现点击按钮弹出本地窗口,选择自定义保存路径
这个不用代码实现(网上也找不到方法可以调出另存为窗口),更改浏览器设置就可以,否则,现在的浏览器都是默认直接保存到下载路径中
545 3
|
1月前
|
Web App开发 开发框架 前端开发
移动端window.open跳转链接时,iOS没有反应的问题
【10月更文挑战第9天】在移动端使用 `window.open` 跳转链接时,iOS 可能无响应,原因是 iOS 的安全策略和弹出窗口阻止功能。解决方法包括:确保在用户交互后触发 `window.open`,将目标设置为 `_self`,使用锚点链接模拟跳转,或利用专门的移动端框架。需综合考虑这些方案以优化用户体验。
564 61
|
13天前
|
移动开发 前端开发 JavaScript
惊!这些前端技术竟然能让你的网站在移动端大放异彩!
随着互联网技术的发展,移动设备成为主要的上网工具。本文介绍了几种关键的前端技术,包括响应式设计、图片优化、字体选择、HTML5和CSS3的应用、性能优化及手势操作设计,帮助开发者提升网站在移动端的显示效果和用户体验。示例代码展示了如何实现简单的双向绑定功能。
23 3
|
1月前
|
机器学习/深度学习 弹性计算 自然语言处理
前端大模型应用笔记(二):最新llama3.2小参数版本1B的古董机测试 - 支持128K上下文,表现优异,和移动端更配
llama3.1支持128K上下文,6万字+输入,适用于多种场景。模型能力超出预期,但处理中文时需加中英翻译。测试显示,其英文支持较好,中文则需改进。llama3.2 1B参数量小,适合移动端和资源受限环境,可在阿里云2vCPU和4G ECS上运行。
|
1月前
|
编解码 前端开发 UED
前端:移动端视口配置
移动端视口配置是指针对移动设备浏览器设置视口的宽度、高度和缩放等属性,以确保网页能根据不同的屏幕尺寸和分辨率进行适配,提供更好的用户体验。合理的视口配置是移动优先设计的关键环节。
|
2月前
|
前端开发 数据安全/隐私保护
【前端web入门第二天】03 表单-下拉菜单 文本域 label标签 按钮 【附注册信息综合案例】
本文档详细介绍了HTML表单的多种元素及其用法,包括下拉菜单(`&lt;select&gt;` 和 `&lt;option&gt;`)、文本域(`&lt;textarea&gt;`)、标签解释(`&lt;label&gt;`)、各类按钮(`&lt;button&gt;`)及表单重置功能、无语义布局标签(`&lt;div&gt;` 和 `&lt;span&gt;`)以及字符实体的应用。此外,还提供了一个完整的注册信息表单案例,涵盖个人信息、教育经历和工作经历等部分,展示了如何综合运用上述元素构建实用的表单。
【前端web入门第二天】03 表单-下拉菜单 文本域 label标签 按钮 【附注册信息综合案例】
|
6月前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
285 0
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
3月前
|
前端开发 JavaScript 开发者
前端JS按钮点击事件、跳出弹窗、遮罩的实战示例
本文提供了一个前端JS按钮点击事件、弹出式窗口和遮罩层的实战示例,包括HTML、CSS和JavaScript的具体实现代码,以及功能解析,演示了如何实现按钮点击后触发弹窗显示和遮罩层,并在2秒后自动关闭或点击遮罩层关闭弹窗的效果。
前端JS按钮点击事件、跳出弹窗、遮罩的实战示例
|
3月前
|
前端开发
前端ElementPlus框架中的几种图标按钮使用方式
本文介绍了如何在Element Plus前端框架中使用带有图标的按钮,包括设置按钮大小、图标大小、按钮类型以及如何为图标添加点击事件。
335 0
|
4月前
|
存储 前端开发 JavaScript
前端菜单及按钮权限拦截,实现方案及思路
此实现方案基于vue框架,并需要依赖vue项目相关的库,router、store等等;前端同学要与后端同学协商,常规是让后端返回一个树结构的菜单数据,并且将所有的涉及权限控制的页面path给到后端,如果是按钮,需要把所有的按钮 code 码统一下,这是前期工作,很重要。
下一篇
无影云桌面