js绘制购物车抛物线动画


Posted in Javascript onNovember 18, 2020

天猫将商品加入购物车会有一个抛物线动画,告诉用户操作成功以及购物车的位置,业务中需要用到类似的效果,记录一下实现过程备忘,先上demo

js绘制购物车抛物线动画 

一开始没有想到用抛物线函数去做,也已经忘记还有这么个函数了,想着抛物线本质上就是向右和向上方向各有一个速度(就上面的demo而言),向右的速度匀速,向上的速度递减,减到0后再反方向递增,元素的left和top值随时间递增而改变,元素运动轨迹就是抛物线,这个思路不具备通用性,实现也比较复杂,放弃了。

js绘制购物车抛物线动画 

之后参考了张鑫旭用抛物线函数的实现方式和愚人码头的改进,豁然开朗。

思路我再捋一捋,抛物线函数y = a*x*x + b*x + c ,其中a不等于0,a、b、c为常数。x、y为抛物线经过的坐标;a决定抛物线的开口方向,a>0开口向上,a<0开口向下。很明显天猫的抛物线开口向下,a还决定开口的大小,值越小开口越大,抛物线越平顺,反之抛物线越陡。所以a的值可以自定义,等于是已知两个坐标(起点和终点坐,即元素left、top值),求两个未知数,初中的数学就学过,二元二次方程。

y1 = a*x1*x1 + b*x1 + c
y2 = a*x2*x2 + b*x2 + c 

a已知,代入两个已知坐标[x1, y1][x2, y2]可以得出b、c的值,x和y的对应关系有了。

不管抛物线开口向上还是向下,元素在水平方向上移动的速度不变,即left值匀速改变,可以设定抛物线运动时间t,元素在水平方向上的速度为speedx =(x2 - x1)/t,设置一个定时器,每30ms执行一次,left值在每次定时器执行后的值为当前的x = speedx * 定时器已执行时长,再代入函数y = a*x*x + b*x + c得到top值,由于这一切的计算都建立在起点坐标平移到原点(终点也随之平移)的基础上,所以最终设置运动元素的left/top值的时候必须将起点元素的初始left/top值加上。具体请F12查看demo代码。

主要代码:

/**
 * js抛物线动画
 * @param {[object]} origin [起点元素]
 * @param {[object]} target [目标点元素]
 * @param {[object]} element [要运动的元素]
 * @param {[number]} a [抛物线弧度]
 * @param {[number]} time [动画执行时间]
 * @param {[function]} callback [抛物线执行完成后回调]
 */
 var parabola = function(config){
 var b = 0,
  INTERVAL = 15,
  timer = null,
  x1,y1,x2,y2,originx,originy,diffx,diffy;

 this.config = config || {};
 // 起点
 this.origin = $(this.config.origin)||null;
 // 终点
 this.target = $(this.config.target)||null;
 // 运动的元素
 this.element = $(this.config.element)||null;
 // 曲线弧度
 this.a = this.config.a || 0.004;
 // 运动时间(ms)
 this.time = this.config.time || 1000;

 this.init = function(){
  x1 = this.origin.offset().left;
  y1 = this.origin.offset().top;
  x2 = this.target.offset().left;
  y2 = this.target.offset().top;
  originx = x1;
  originy = y1;
  diffx = x2-x1;
  diffy = y2-y1,
  speedx = diffx/this.time;

  // 已知a, 根据抛物线函数 y = a*x*x + b*x + c 将抛物线起点平移到坐标原点[0, 0],终点随之平移,那么抛物线经过原点[0, 0] 得出c = 0;
  // 终点平移后得出:y2-y1 = a*(x2 - x1)*(x2 - x1) + b*(x2 - x1)
  // 即 diffy = a*diffx*diffx + b*diffx;
  // 可求出常数b的值
  b = (diffy - this.a*diffx*diffx)/diffx;
  this.element.css({
  left: x1,
  top: y1
  })
  return this;
 }

 // 确定动画方式
 this.moveStyle = function(){
  var moveStyle = 'position',
  testDiv = document.createElement('div');
  if('placeholder' in testDiv){
  ['','ms','moz','webkit'].forEach(function(pre){
   var transform = pre + (pre ? 'T' : 't') + 'ransform';
   if(transform in testDiv.style){
   moveStyle = transform;
   }
  })
  }
  return moveStyle;
 }

 this.move = function(){
  var start = new Date().getTime(),
  moveStyle = this.moveStyle(),
  _this = this;
  timer = setInterval(function(){
  if(new Date().getTime() - start > _this.time){
   clearInterval(timer);
   _this.element.css({
   left: x2,
   top: y2
   })
   typeof _this.config.callback === 'function' && _this.config.callback(_this.element);
   return;
  }
  x = speedx * (new Date().getTime() - start);
  y = _this.a*x*x + b*x;
  if(moveStyle === 'position'){
   _this.element.css({
   left: x+originx,
   top: y+originy
   })
  }else{
   if(window.requestAnimationFrame){
   window.requestAnimationFrame(_this.element[0].style[moveStyle] = 'translate('+x+'px,'+y+'px)');
   }else{
   _this.element[0].style[moveStyle] = 'translate('+x+'px,'+y+'px)';
   }
  }
  },INTERVAL)
  return this;
 }

 this.init();
 }

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

Javascript 相关文章推荐
比较搞笑的js陷阱题
Feb 07 Javascript
JQuery开发的数独游戏代码
Oct 29 Javascript
javascript 系统文件夹文件操作及参数介绍
Jan 08 Javascript
js操作label给label赋值及取label的值示例
Nov 07 Javascript
javascript if条件判断方法小结
May 17 Javascript
浅谈关于axios和session的一些事
Jul 13 Javascript
AngularJS中下拉框的基本用法示例
Oct 11 Javascript
利用JS判断客户端类型你应该知道的四种方法
Dec 22 Javascript
angular 数据绑定之[]和{{}}的区别
Sep 25 Javascript
js实现固定区域内的不重叠随机圆
Oct 24 Javascript
微信小程序实现一个简单swiper代码实例
Dec 30 Javascript
Vue中父子组件的值传递与方法传递
Sep 28 Javascript
基于jQuery实现发送短信验证码后的倒计时功能(无视页面关闭)
Sep 02 #Javascript
基于JS实现发送短信验证码后的倒计时功能(无视页面刷新,页面关闭不进行倒计时功能)
Sep 02 #Javascript
node.js中module.exports与exports用法上的区别
Sep 02 #Javascript
AngularJs Scope详解及示例代码
Sep 01 #Javascript
AngularJs Modules详解及示例代码
Sep 01 #Javascript
AngularJs IE Compatibility 兼容老版本IE
Sep 01 #Javascript
AngularJs 国际化(I18n/L10n)详解
Sep 01 #Javascript
You might like
Eclipse的PHP插件PHPEclipse安装和使用
2014/07/20 PHP
PHP多进程编程之僵尸进程问题的理解
2017/10/15 PHP
Thinkphp 3.2框架使用Redis的方法详解
2019/10/24 PHP
JavaScript1.6数组新特性介绍以及JQuery的几个工具方法
2013/12/06 Javascript
Jquery获取和修改img的src值的方法
2014/02/17 Javascript
jquery查找tr td 示例模拟
2014/05/08 Javascript
node+express+jade制作简单网站指南
2014/11/26 Javascript
自己封装的常用javascript函数分享
2015/01/07 Javascript
分享9个最好用的JavaScript开发工具和代码编辑器
2015/03/24 Javascript
JS实现方向键切换输入框焦点的方法
2015/08/19 Javascript
window.onload使用指南
2015/09/13 Javascript
浅析javascript函数表达式
2016/02/10 Javascript
jQuery EasyUI右键菜单实现关闭标签/选项卡
2016/10/10 Javascript
JQuery Ajax WebService传递参数的简单实例
2016/11/02 Javascript
Vue2.0 从零开始_环境搭建操作步骤
2017/06/14 Javascript
vue动画打包后失效问题的解决方法
2018/09/18 Javascript
2019 年编写现代 JavaScript 代码的5个小技巧(小结)
2019/01/15 Javascript
[01:07]DOTA2次级职业联赛 - Fpb战队宣传片
2014/12/01 DOTA
[55:42]VG vs VGJ.T 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
web.py在模板中输出美元符号的方法
2014/08/26 Python
python私有属性和方法实例分析
2015/01/15 Python
Python输出PowerPoint(ppt)文件中全部文字信息的方法
2015/04/28 Python
python简单贪吃蛇开发
2019/01/28 Python
Pandas的数据过滤实现
2021/01/15 Python
python实现简单的学生管理系统
2021/02/22 Python
如何使用html5与css3完成google涂鸦动画
2012/12/16 HTML / CSS
英国最大的汽车配件在线商店:Euro Car Parts
2019/09/30 全球购物
业务员岗位职责范本
2013/12/15 职场文书
学雷锋演讲稿汇总
2014/05/10 职场文书
售后服务承诺书模板
2014/05/21 职场文书
小学生运动会通讯稿
2014/09/23 职场文书
优秀教师先进事迹材料
2014/12/15 职场文书
护士个人年度总结范文
2015/02/13 职场文书
实习介绍信范文
2015/05/05 职场文书
管理失职检讨书
2015/05/05 职场文书
MySQL RC事务隔离的实现
2022/03/31 MySQL