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 相关文章推荐
文字幻灯片
Jun 26 Javascript
JavaScript的变量作用域深入理解
Oct 25 Javascript
js 通用javascript函数库整理
Aug 14 Javascript
JS设置cookie、读取cookie
Feb 24 Javascript
Bootstrap学习笔记之js组件(4)
Jun 12 Javascript
vue开发心得和技巧分享
Oct 27 Javascript
Vue.js自定义指令的用法与实例解析
Jan 18 Javascript
easyui datagrid 表格中操作栏 按钮图标不显示的解决方法
Jul 27 Javascript
JS+Ajax实现百度智能搜索框
Aug 04 Javascript
微信小程序实现获取自己所处位置的经纬度坐标功能示例
Nov 30 Javascript
JavaScript时间戳与时间日期间相互转换
Dec 11 Javascript
使用p5.js临摹动态图形
Oct 23 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
php at(@)符号的用法简介
2009/07/11 PHP
让CodeIgniter数据库缓存自动过期的处理的方法
2014/06/12 PHP
PHP实现的简单缓存类
2015/07/29 PHP
thinkphp框架无限级栏目的排序功能实现方法示例
2020/03/29 PHP
Nigma vs Alliance BO5 第一场2.14
2021/03/10 DOTA
javaScript 简单验证代码(用户名,密码,邮箱)
2009/09/28 Javascript
JavaScript arguments 多参传值函数
2010/10/24 Javascript
JS中eval函数的使用示例
2013/07/21 Javascript
使用Object.defineProperty实现简单的js双向绑定
2016/04/15 Javascript
超全面的javascript中变量命名规则
2017/02/09 Javascript
js时间查询插件使用详解
2017/04/07 Javascript
js截取字符串功能的实现方法
2017/09/27 Javascript
关于Vue组件库开发详析
2018/07/01 Javascript
vue项目使用微信公众号支付总结及遇到的坑
2018/10/23 Javascript
Python中条件选择和循环语句使用方法介绍
2013/03/13 Python
在Python的Flask中使用WTForms表单框架的基础教程
2016/06/07 Python
Python实现打印螺旋矩阵功能的方法
2017/11/21 Python
python删除服务器文件代码示例
2018/02/09 Python
使用Python监视指定目录下文件变更的方法
2018/10/15 Python
python for 循环获取index索引的方法
2019/02/01 Python
python用线性回归预测股票价格的实现代码
2019/09/04 Python
python zip()函数使用方法解析
2019/10/31 Python
完美解决python针对hdfs上传和下载的问题
2020/06/05 Python
Python如何急速下载第三方库详解
2020/11/02 Python
计算机专业应届毕业生自荐信
2013/09/26 职场文书
大学生求职推荐信
2013/11/27 职场文书
会计电算化专业毕业生自荐信
2013/12/20 职场文书
大学军训通讯稿
2014/01/13 职场文书
优秀技术工人先进材料
2014/02/17 职场文书
《千年梦圆在今朝》教学反思
2014/02/24 职场文书
医院护士见习期自我鉴定
2014/04/10 职场文书
家长会欢迎标语
2014/06/24 职场文书
新兵入伍心得体会
2014/09/04 职场文书
入学证明
2015/06/23 职场文书
2016年党员公开承诺书格式范文
2016/03/24 职场文书
详解如何修改nginx的默认端口
2021/03/31 Servers