视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
parabola.js抛物线与加入购物车效果的示例代码
2020-11-27 22:27:12 责编:小采
文档

在做购物车的时候发现一个很好用抛物线特效parabola.js,可先点击DEMO体验下。下面贴出一些关键代码,具体代码可在GitHub上查看

parabola.js

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;
};

实现

// body
<div class="container">
 ![](dist/01.png)
 <center>点击加入购物车查看效果</center>

 <!--动画图片-->
 <div class="img-element" id="imgElement">
 ![](dist/02.jpg)
 </div>
 <!--购物车-->
 <div class="shop-cart" id="shopCart"></div>

 <span class="shop-cart-num">0</span>
 <div class="add-shop-cart"><!--加入购物车--></div>
</div>
// script
// 起始位置元素
var imgElement = document.querySelector('#imgElement'),
 // 终点位置元素
 shopCartElement = document.querySelector('#shopCart'),
 // 购物车数量
 proNum = 0;

// 初始化抛物线动画
var myParabola = funParabola(imgElement, shopCartElement, {
 speed: 100,// 每帧移动的像素大小
 curvature: 0.005,// 实际指焦点到准线的距离
 complete: function () {
 imgElement.style.visibility = "hidden";
 $('.shop-cart-num').text(++proNum);
 }
});
// 绑定加入购物车事件
$('.add-shop-cart').click(function () {
 // 重置位置
 $('#imgElement').css({ left: '70px', bottom: '25px', visibility: 'visible' });

 myParabola.position().move();
});

效果图

下载本文
显示全文
专题