js实现商品抛物线加入购物车特效


Posted in Javascript onNovember 18, 2020

本文实例为大家分享了js实现商品抛物线加入购物车动画代码,供大家参考,具体内容如下

 js实现商品抛物线加入购物车特效

parapola.js

/*!
 * by zhangxinxu(.com) 2012-12-27
 * you can visit http://www.zhangxinxu.com/wordpress/?p=3855 to get more infomation
 * under MIT license
*/
var funParabola = function(element, target, options) {
 /*
  * 网页模拟现实需要一个比例尺
  * 如果按照1像素就是1米来算,显然不合适,因为页面动不动就几百像素
  * 页面上,我们放两个物体,200~800像素之间,我们可以映射为现实世界的2米到8米,也就是100:1
  * 不过,本方法没有对此有所体现,因此不必在意
 */
 
 var defaults = {
  speed: 166.67, // 每帧移动的像素大小,每帧(对于大部分显示屏)大约16~17毫秒
  curvature: 0.001, // 实际指焦点到准线的距离,你可以抽象成曲率,这里模拟扔物体的抛物线,因此是开口向下的
  progress: function() {},
  complete: function() {}
 };
 
 var params = {}; options = options || {};
 
 for (var key in defaults) {
  params[key] = options[key] || defaults[key];
 }
 
 var exports = {
  mark: function() { return this; },
  position: function() { return this; },
  move: function() { return this; },
  init: function() { return this; }
 };
 
 /* 确定移动的方式 
  * IE6-IE8 是margin位移
  * IE9+使用transform
 */
 var moveStyle = "margin", testDiv = document.createElement("div");
 if ("oninput" in testDiv) {
  ["", "ms", "webkit"].forEach(function(prefix) {
   var transform = prefix + (prefix? "T": "t") + "ransform";
   if (transform in testDiv.style) {
    moveStyle = transform;
   }
  });  
 }
 
 // 根据两点坐标以及曲率确定运动曲线函数(也就是确定a, b的值)
 /* 公式: y = a*x*x + b*x + c;
 */
 var a = params.curvature, b = 0, c = 0;
 
 // 是否执行运动的标志量
 var flagMove = true;
 
 if (element && target && element.nodeType == 1 && target.nodeType == 1) {
  var rectElement = {}, rectTarget = {};
  
  // 移动元素的中心点位置,目标元素的中心点位置
  var centerElement = {}, centerTarget = {};
  
  // 目标元素的坐标位置
  var coordElement = {}, coordTarget = {};
  
  // 标注当前元素的坐标
  exports.mark = function() {
   if (flagMove == false) return this;
   if (typeof coordElement.x == "undefined") this.position();
   element.setAttribute("data-center", [coordElement.x, coordElement.y].join());
   target.setAttribute("data-center", [coordTarget.x, coordTarget.y].join());
   return this;
  }
  
  exports.position = function() {
   if (flagMove == false) return this;
   
   var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft,
    scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
   
   // 初始位置
   if (moveStyle == "margin") {
    element.style.marginLeft = element.style.marginTop = "0px";
   } else {
    element.style[moveStyle] = "translate(0, 0)";
   }
   
   // 四边缘的坐标
   rectElement = element.getBoundingClientRect();
   rectTarget = target.getBoundingClientRect();
   
   // 移动元素的中心点坐标
   centerElement = {
    x: rectElement.left + (rectElement.right - rectElement.left) / 2 + scrollLeft,
    y: rectElement.top + (rectElement.bottom - rectElement.top) / 2 + scrollTop
   };
   
   // 目标元素的中心点位置
   centerTarget = {
    x: rectTarget.left + (rectTarget.right - rectTarget.left) / 2 + scrollLeft,
    y: rectTarget.top + (rectTarget.bottom - rectTarget.top) / 2 + scrollTop  
   };
   
   // 转换成相对坐标位置
   coordElement = {
    x: 0,
    y: 0 
   };
   coordTarget = {
    x: -1 * (centerElement.x - centerTarget.x),
    y: -1 * (centerElement.y - centerTarget.y) 
   };
   
   /*
    * 因为经过(0, 0), 因此c = 0
    * 于是:
    * y = a * x*x + b*x;
    * y1 = a * x1*x1 + b*x1;
    * y2 = a * x2*x2 + b*x2;
    * 利用第二个坐标:
    * b = (y2+ a*x2*x2) / x2
   */
   // 于是
   b = (coordTarget.y - a * coordTarget.x * coordTarget.x) / coordTarget.x; 
   
   return this;
  };  
  
  // 按照这个曲线运动
  exports.move = function() {
   // 如果曲线运动还没有结束,不再执行新的运动
   if (flagMove == false) return this;
   
   var startx = 0, rate = coordTarget.x > 0? 1: -1;

   var step = function() {
    // 切线 y'=2ax+b
    var tangent = 2 * a * startx + b; // = y / x
    // y*y + x*x = speed
    // (tangent * x)^2 + x*x = speed
    // x = Math.sqr(speed / (tangent * tangent + 1));
    startx = startx + rate * Math.sqrt(params.speed / (tangent * tangent + 1));
    
    // 防止过界
    if ((rate == 1 && startx > coordTarget.x) || (rate == -1 && startx < coordTarget.x)) {
     startx = coordTarget.x;
    }
    var x = startx, y = a * x * x + b * x;
    
    // 标记当前位置,这里有测试使用的嫌疑,实际使用可以将这一行注释
    element.setAttribute("data-center", [Math.round(x), Math.round(y)].join());
    
    // x, y目前是坐标,需要转换成定位的像素值
    if (moveStyle == "margin") {
     element.style.marginLeft = x + "px";
     element.style.marginTop = y + "px";
    } else {
     element.style[moveStyle] = "translate("+ [x + "px", y + "px"].join() +")";
    }
    
    if (startx !== coordTarget.x) {
     params.progress(x, y);
     window.requestAnimationFrame(step); 
    } else {
     // 运动结束,回调执行
     params.complete();
     flagMove = true; 
    }
   };
   window.requestAnimationFrame(step);
   flagMove = false;
   
   return this;
  };
  
  // 初始化方法
  exports.init = function() {
   this.position().mark().move();
  };
 }
 
 return exports;
};

/*! requestAnimationFrame.js
 * by zhangxinxu 2013-09-30
*/
(function() {
 var lastTime = 0;
 var vendors = ['webkit', 'moz'];
 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
  window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
  window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // name has changed in Webkit
          window[vendors[x] + 'CancelRequestAnimationFrame'];
 }

 if (!window.requestAnimationFrame) {
  window.requestAnimationFrame = function(callback, element) {
   var currTime = new Date().getTime();
   var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
   var id = window.setTimeout(function() {
    callback(currTime + timeToCall);
   }, timeToCall);
   lastTime = currTime + timeToCall;
   return id;
  };
 }
 if (!window.cancelAnimationFrame) {
  window.cancelAnimationFrame = function(id) {
   clearTimeout(id);
  };
 }
}());

使用:

/* 元素 */
var element = document.getElementById("element"), 
 target = document.getElementById("target");
// 抛物线元素的的位置标记
var parabola = funParabola(element, target).mark();
// 抛物线运动的触发
document.body.onclick = function() {
 element.style.marginLeft = "0px";
 element.style.marginTop = "0px";
 parabola.init();
};

加入购物车实战:

/* 本demo演示脚本基于ieBetter.js, 项目地址:https://github.com/zhangxinxu/ieBetter.js */

// 元素以及其他一些变量
var eleFlyElement = document.querySelector("#flyItem"), eleShopCart = document.querySelector("#shopCart");
var numberItem = 0;
// 抛物线运动
var myParabola = funParabola(eleFlyElement, eleShopCart, {
 speed: 400,
 curvature: 0.002, 
 complete: function() {
  eleFlyElement.style.visibility = "hidden";
  eleShopCart.querySelector("span").innerHTML = ++numberItem;
 }
});
// 绑定点击事件
if (eleFlyElement && eleShopCart) {
 [].slice.call(document.getElementsByClassName("btnCart")).forEach(function(button) {
  button.addEventListener("click", function() {
   // 滚动大小
   var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || 0,
    scrollTop = document.documentElement.scrollTop || document.body.scrollTop || 0;

   eleFlyElement.style.left = event.clientX + scrollLeft + "px";
   eleFlyElement.style.top = event.clientY + scrollTop + "px";
   eleFlyElement.style.visibility = "visible";
   
   // 需要重定位
   myParabola.position().move(); 
  });
 });
}

以上就是本文的全部内容,希望对大家的学习有所帮助。

Javascript 相关文章推荐
判断JavaScript对象是否可用的最正确方法分析
Oct 03 Javascript
jquery 批量上传图片实现代码
Jan 28 Javascript
详解JavaScript中的Unescape()和String() 函数
Nov 09 Javascript
ECharts仪表盘实例代码(附源码下载)
Feb 18 Javascript
JavaScript学习笔记之创建对象
Mar 25 Javascript
学习使用bootstrap3栅格系统
Apr 12 Javascript
JS中this上下文对象使用方式
Oct 09 Javascript
jQuery EasyUI Draggable拖动组件
Mar 01 Javascript
JavaWeb表单及时验证功能在输入后立即验证(含用户类型,性别,爱好...的验证)
Jun 09 Javascript
AngularJS 仿微信图片手势缩放的实例
Sep 28 Javascript
node.js的exports、module.exports与ES6的export、export default深入详解
Oct 26 Javascript
vue前端框架—Mint UI详解(更适用于移动端)
Apr 30 Javascript
js类式继承与原型式继承详解
Apr 07 #Javascript
javascript原型继承工作原理和实例详解
Apr 07 #Javascript
浅析JS原型继承与类的继承
Apr 07 #Javascript
AngularJs 弹出模态框(model)
Apr 07 #Javascript
详解AngularJS 模态对话框
Apr 07 #Javascript
分离与继承的思想实现图片上传后的预览功能:ImageUploadView
Apr 07 #Javascript
jQuery动态添加
Apr 07 #Javascript
You might like
php抓取https的内容的代码
2010/04/06 PHP
PHP人民币金额数字转中文大写的函数代码
2013/02/27 PHP
PHP分享图片的生成方法
2018/04/25 PHP
对setInterval在火狐和chrome切换标签产生奇怪的效果之探索,与解决方案!
2011/10/29 Javascript
网页中返回顶部代码(多种方法)另附注释说明
2013/04/24 Javascript
jquery实现拖动效果(代码分享)
2017/01/25 Javascript
使用openSpeDiv方法实现Ecshop登录弹窗框效果
2017/03/13 Javascript
基于AngularJS的拖拽文件上传的实例代码
2017/07/15 Javascript
浅谈nodejs中的类定义和继承的套路
2017/07/26 NodeJs
解读ES6中class关键字
2017/11/20 Javascript
使用javascript函数编写简单银行取钱存钱流程
2018/05/26 Javascript
JavaScript中的ES6 Proxy的具体使用
2019/06/16 Javascript
[37:45]完美世界DOTA2联赛PWL S3 LBZS vs Phoenix 第二场 12.09
2020/12/11 DOTA
理解Python中的类与实例
2015/04/27 Python
python3抓取中文网页的方法
2015/07/28 Python
Python字符串拼接六种方法介绍
2017/12/18 Python
python机器学习之神经网络(二)
2017/12/20 Python
Python实现扣除个人税后的工资计算器示例
2018/03/26 Python
python中从str中提取元素到list以及将list转换为str的方法
2018/06/26 Python
Python设计模式之建造者模式实例详解
2019/01/17 Python
django模板加载静态文件的方法步骤
2019/03/01 Python
Python3离线安装Requests模块问题
2019/10/13 Python
pandas 空数据处理方法详解
2019/11/02 Python
selenium 多窗口切换的实现(windows)
2020/01/18 Python
pyqt5中动画的使用详解
2020/04/01 Python
Numpy 理解ndarray对象的示例代码
2020/04/03 Python
Python logging模块handlers用法详解
2020/08/14 Python
Python 图片处理库exifread详解
2021/02/25 Python
Julep官网:美容产品和指甲油
2017/02/25 全球购物
英国最大的宝石首饰超市:QP Jewellers
2018/09/23 全球购物
加拿大领先家居家具网上购物:Aosom.ca
2020/05/27 全球购物
迎八一活动主题
2014/01/31 职场文书
股东授权委托书范文
2014/09/13 职场文书
经验交流材料格式
2014/12/30 职场文书
餐饮店长岗位职责
2015/04/14 职场文书
JAVA长虹键法之建造者Builder模式实现
2022/04/10 Java/Android