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 相关文章推荐
functional继承模式 摘自javascript:the good parts
Jun 20 Javascript
映彩衣的js随笔(js图片切换效果)
Jul 31 Javascript
刷新页面的几种方法小结(JS,ASP.NET)
Jan 07 Javascript
jsp网页搜索结果中实现选中一行使其高亮
Feb 17 Javascript
yui3的AOP(面向切面编程)和OOP(面向对象编程)
May 01 Javascript
jquery中ready()函数执行的时机和window的load事件比较
Jun 22 Javascript
浅谈JSON.parse()和JSON.stringify()
Jul 14 Javascript
JS与jQ读取xml文件的方法
Dec 08 Javascript
三分钟带你玩转jQuery.noConflict()
Feb 15 Javascript
js中document.referrer实现移动端返回上一页
Feb 22 Javascript
vue2.0自定义指令示例代码详解
Apr 25 Javascript
vue element upload实现图片本地预览
Aug 20 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
全国FM电台频率大全 - 15 山东省
2020/03/11 无线电
PHP开发文件系统实例讲解
2006/10/09 PHP
smarty模板判断数组为空的方法
2015/06/10 PHP
PHP实现的分解质因数操作示例
2018/08/01 PHP
jQuery autocomplate 自扩展插件、自动完成示例代码
2011/03/28 Javascript
通过jquery 获取URL参数并进行转码
2014/08/18 Javascript
jquery 操作css样式、位置、尺寸方法汇总
2014/11/28 Javascript
node.js中的console.info方法使用说明
2014/12/09 Javascript
移动端JQ插件hammer使用详解
2015/07/03 Javascript
jquery在ie7下选择器的问题导致append失效的解决方法
2016/01/10 Javascript
Javascript实现汉字和拼音互转的终极方案
2016/10/19 Javascript
Vue方法与事件处理器详解
2016/12/01 Javascript
浅谈jQuery中的$.extend方法来扩展JSON对象
2017/02/12 Javascript
jquery仿京东商品放大浏览页面
2017/06/06 jQuery
jquery实现垂直手风琴导航栏
2020/02/18 jQuery
[02:10]DOTA2亚洲邀请赛 EG战队出场宣传片
2015/02/07 DOTA
[01:23:24]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Elephant BO3 第三场 2月7日
2021/03/11 DOTA
python的urllib模块显示下载进度示例
2014/01/17 Python
Python中DJANGO简单测试实例
2015/05/11 Python
Python django实现简单的邮件系统发送邮件功能
2017/07/14 Python
Python cookbook(数据结构与算法)从序列中移除重复项且保持元素间顺序不变的方法
2018/03/13 Python
python 获取当天每个准点时间戳的实例
2018/05/22 Python
Python3中关于cookie的创建与保存
2018/10/21 Python
python3.6实现学生信息管理系统
2019/02/21 Python
python 代码实现k-means聚类分析的思路(不使用现成聚类库)
2020/06/01 Python
路易威登和香奈儿手袋:LuxeDH
2017/01/12 全球购物
Miller Harris官网:英国小众香水品牌
2020/09/24 全球购物
Java中会存在内存泄漏吗,请简单描述
2016/12/22 面试题
保卫科工作岗位职责
2014/03/01 职场文书
员工工作表现评语
2014/04/26 职场文书
幽默自我介绍演讲稿
2014/08/21 职场文书
基层党支部整改方案
2014/10/25 职场文书
辛德勒的名单观后感
2015/06/03 职场文书
承诺书怎么写 ?
2019/04/16 职场文书
导游词之苏州寒山寺
2019/12/05 职场文书
再谈python_tkinter弹出对话框创建
2022/03/20 Python