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 相关文章推荐
表单提交验证类
Jul 14 Javascript
imgAreaSelect 中文文档帮助说明
Oct 08 Javascript
JavaScript中instanceof与typeof运算符的用法及区别详细解析
Nov 19 Javascript
JS中类或对象的定义说明
Mar 10 Javascript
JavaScript实现数组在指定位置插入若干元素的方法
Apr 06 Javascript
微信小程序 教程之模块化
Oct 17 Javascript
jQuery自定义多选下拉框效果
Jun 19 jQuery
浅谈Express异步进化史
Sep 09 Javascript
基于Vue 实现一个中规中矩loading组件
Apr 03 Javascript
vue实现自定义H5视频播放器的方法步骤
Jul 01 Javascript
原生JS实现相邻月份日历
Oct 13 Javascript
vue-resource 拦截器interceptors使用详解
Jan 18 Vue.js
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抽象类 介绍
2012/06/13 PHP
Laravel 5框架学习之环境与配置
2015/04/08 PHP
Zend Framework入门教程之Zend_Mail用法示例
2016/12/08 PHP
Jquery Ajax学习实例3 向WebService发出请求,调用方法返回数据
2010/03/16 Javascript
jQuery中 noConflict() 方法使用
2013/04/25 Javascript
jQuery仿Excel表格编辑功能的实现代码
2013/05/01 Javascript
浅析jQuery对select操作小结(遍历option,操作option)
2013/07/04 Javascript
js简单实现点击左右运动的方法
2015/04/10 Javascript
JavaScript正则表达式匹配 div  style标签
2016/03/15 Javascript
jquery实现弹窗功能(窗口居中显示)
2017/02/27 Javascript
JavaScript运动框架 链式运动到完美运动(五)
2017/05/18 Javascript
基于Vue实例生命周期(全面解析)
2017/08/16 Javascript
javaScript和jQuery自动加载简单代码实现方法
2017/11/24 jQuery
node.js中fs文件系统目录操作与文件信息操作
2018/02/24 Javascript
小程序指纹验证的实现代码
2018/12/04 Javascript
js中Generator函数的深入讲解
2019/04/07 Javascript
解决VUE-Router 同一页面第二次进入不刷新的问题
2020/07/22 Javascript
解决seaborn在pycharm中绘图不出图的问题
2018/05/24 Python
python3 拼接字符串的7种方法
2018/09/12 Python
python下的opencv画矩形和文字注释的实现方法
2019/07/09 Python
利用setuptools打包python程序的方法步骤
2020/01/18 Python
python使用html2text库实现从HTML转markdown的方法详解
2020/02/21 Python
django 数据库 get_or_create函数返回值是tuple的问题
2020/05/15 Python
浅谈Python中的生成器和迭代器
2020/06/19 Python
通过代码实例解析Pytest运行流程
2020/08/20 Python
有趣的流行文化T恤、马克杯、手机壳和更多:Look Human
2019/01/07 全球购物
Nobody Denim官网:购买高级女士牛仔裤
2021/03/15 全球购物
军人违纪检讨书
2014/02/04 职场文书
自荐信如何制作?
2014/02/21 职场文书
幼儿园师德演讲稿
2014/05/06 职场文书
初中教师个人总结
2015/02/10 职场文书
美丽的大脚观后感
2015/06/03 职场文书
企业文化学习心得体会
2016/01/21 职场文书
六年级数学教学反思
2016/02/16 职场文书
工作总结之小学教师体育工作范文(3篇)
2019/10/07 职场文书
动画《朋友游戏》公开佐藤友生绘制的开播纪念绘
2022/04/06 日漫