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 相关文章推荐
JavaScript 继承的实现
Jul 09 Javascript
初试jQuery EasyUI 使用介绍
Apr 01 Javascript
js循环改变div颜色具体方法
Jun 25 Javascript
限制上传文件大小和格式的jQuery插件实例
Jan 24 Javascript
javascript实现下班倒计时效果的方法(可桌面通知)
Jul 10 Javascript
JS实现可自定义大小,可双击关闭的弹出层效果
Oct 16 Javascript
基于javascript实现页面加载loading效果
Sep 15 Javascript
javascript+HTML5 Canvas绘制转盘抽奖
May 16 Javascript
浅谈JavaScript作用域和闭包
Sep 18 Javascript
从零开始学习搭建React脚手架项目
Aug 23 Javascript
vue 路由子组件created和mounted不起作用的解决方法
Nov 05 Javascript
详解一些适用于Node.js的命名约定
Dec 08 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
Mysql中分页查询的两个解决方法比较
2013/05/02 PHP
PHP中Fatal error session_start()错误解决步骤
2014/08/05 PHP
php打印一个边长为N的实心和空心菱型的方法
2015/03/02 PHP
php实现微信企业转账功能
2018/10/02 PHP
javascript之通用简单的table选项卡实现(二)
2010/05/09 Javascript
jquery $.each 和for怎么跳出循环终止本次循环
2013/09/27 Javascript
zTree插件之多选下拉菜单实例代码
2013/11/06 Javascript
javascript从image转换为base64位编码的String
2014/07/29 Javascript
JavaScript的类型、值和变量小结
2015/07/09 Javascript
JavaScript实现横线提示输入验证码随输入验证码输入消失的方法
2016/09/24 Javascript
JS实现的验证身份证及获取地区功能示例
2017/01/16 Javascript
Vue.js实现微信过渡动画左右切换效果
2017/06/13 Javascript
js+html5实现页面可刷新的倒计时效果
2017/07/15 Javascript
javascript cookie的基本操作(添加和删除)
2017/07/24 Javascript
Extjs 中的 Treepanel 实现菜单级联选中效果及实例代码
2017/08/22 Javascript
react中的ajax封装实例详解
2017/10/17 Javascript
Node.js中,在cmd界面,进入退出Node.js运行环境的方法
2018/05/12 Javascript
浅谈super-vuex使用体验
2018/06/25 Javascript
一篇文章介绍redux、react-redux、redux-saga总结
2019/05/23 Javascript
jQuery 查找元素操作实例小结
2019/10/02 jQuery
微信小程序 生成携带参数的二维码
2019/10/23 Javascript
[01:23:59]2018DOTA2亚洲邀请赛 4.1 小组赛 B组 VP vs Secret
2018/04/03 DOTA
Python采用raw_input读取输入值的方法
2014/08/18 Python
python类和继承用法实例
2015/07/07 Python
对python创建及引用动态变量名的示例讲解
2018/11/10 Python
详解python调用cmd命令三种方法
2019/07/08 Python
Python内存映射文件读写方式
2020/04/24 Python
解决PyCharm无法使用lxml库的问题(图解)
2020/12/22 Python
Python Selenium操作Cookie的实例方法
2021/02/28 Python
船舶专业个人求职信范文
2014/01/02 职场文书
进口业务员岗位职责
2014/04/06 职场文书
活动策划求职信模板
2014/04/21 职场文书
高中班主任评语大全
2014/04/25 职场文书
新闻编辑求职信
2014/07/13 职场文书
三严三实学习心得体会
2014/10/13 职场文书
java获取一个文本文件的编码(格式)信息
2022/09/23 Java/Android