zoukankan      html  css  js  c++  java
  • js加入购物车特效

    本文来源:  http://www.zhangxinxu.com/study/201312/js-parabola-shopping.html

    parabola.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);
            };
        }
    }());

    案例html

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="description" content="JS抛物线动画与购物车效果 » 张鑫旭-鑫空间-鑫生活" />
    <meta name="description" content="张鑫旭web前端学习实例页面 JS抛物线动画与购物车效果" />
    <meta name="keywords" content="抛物线, 动画, javascript" />
    <meta name="author" content="张鑫旭, zhangxixnu" />
    <title>JS抛物线动画与购物车效果 » 张鑫旭-鑫空间-鑫生活</title>
    <link rel="stylesheet" href="../css/demo.css" type="text/css" />
    <link rel="stylesheet" href="../css/hl.css" type="text/css" />
    <style>
    body { overflow-x: hidden; }
    img { vertical-align: bottom; }
    .width_limit {  1194px; margin-left: auto; margin-right: auto; }
    .image_limit { position: relative; }
    .shop_cart {  283px; height: 25px; line-height: 25px; padding-top: 8px; background: url(shopping-cart.png); font-family: 'microsoft yahei'; font-size: 12px; text-indent: 34px; color: #000; position: fixed; right: 10px; bottom: 0; }
    .add_cart_large, .add_cart_small { position: absolute; background: url(about:blank); text-indent: -99em; overflow: hidden; }
    .add_cart_large {  167px; height: 33px; left: 724px; top: 511px; }
    .add_cart_small {  82px; height: 25px; left: 1098px; top: 1014px; }
    
    .fly_item { border: 2px solid #B30000;  50px; height: 50px; overflow: hidden; position: absolute; visibility: hidden; opacity: .5; filter: alpha(opacity=50); }
    </style>
    </head>
    
    <body>
    <div id="header">
        <a href="/" class="logo" title="回到鑫空间-鑫生活首页">
            <img src="http://www.zhangxinxu.com/php/image/zxx_home_logo.png" border="0" />
        </a>
    </div>
    <div id="main">
        <h1>JS抛物线动画与购物车效果实例页面</h1>
        <div id="body" class="light">
            <div id="content" class="show">
                <h3>展示</h3>
                <div class="article_new"><a href="http://www.zhangxinxu.com/wordpress/?p=3855">回到相关文章 »</a></div>
                <div class="demo">
                    <div class="width_limit">
                        <p>下面这个是截图,只有两个“加入购物车”按钮可以点击:</p>
                        <div class="image_limit">
                            <img src="http://image.zhangxinxu.com/image/blog/201412/2013-12-30_103800.png" width="1194" height="1051" alt="天猫某商品页面的部分截图" />
                            <a href="javascript:" class="add_cart_large btnCart" title="加入购物车">加入购物车</a>
                            <a href="javascript:" class="add_cart_small btnCart" title="加入购物车">加入购物车</a>
                           </div>
                    </div>
                    <div id="shopCart" class="shop_cart">购物车 <span>0</span></div>
                    <div id="flyItem" class="fly_item"><img src="/study/201312/item-pic.jpg" width="50" height="50" /></div>
                </div>
                <h3>代码</h3>
                <h5>JS代码:</h5>
                <pre name="code" class="js">
    /* 本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();  
            });
        });
    }
                </pre>
            </div>       
        </div>
    </div>
    
    <script src="http://rawgithub.com/zhangxinxu/ieBetter.js/master/ieBetter.js"></script>
    <script src="/study/201312/parabola.js"></script>
    <script>
    // 元素以及其他一些变量
    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(event) {
                // 滚动大小
                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();            
            });
        });
    }
    </script>
    
    <!-- 以下脚本是无关紧要 -->
    <script type="text/javascript" src="../js/hl_all.js"></script>
    <script type="text/javascript">
        DlHighlight.HELPERS.highlightByName("code", "pre");
    </script>
    <div id="footer">
        Designed &amp; Powerd by <a href="http://www.zhangxinxu.com/">zhangxinxu</a><br />
        Copyright© 张鑫旭-鑫空间-鑫生活<br>
        <a href="http://www.miibeian.gov.cn/" target="_blank">鄂ICP备09015569号</a>      
    </div>
    <div id="ad">
        <script type="text/javascript">    google_ad_client = "pub-0090627341039040";google_ad_slot = "2041257798";google_ad_width = 468;google_ad_height = 60;</script>
        <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
        <script type="text/javascript">
          var _gaq = _gaq || [];
          _gaq.push(['_setAccount', 'UA-11205167-1']);
          _gaq.push(['_trackPageview']);
        
          (function() {
            var ga = document.createElement('script');
             ga.type = 'text/javascript';
             ga.async = true;
            ga.src = 'http://www.google-analytics.com/ga.js';
            var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
          })();
        </script>
    </div>
    </body>
    </html>
  • 相关阅读:
    java入门第一篇:h5和CSS的基础学习及思考。
    Dubbo-入门到精通(一)
    跳表(skipList)的原理和java实现
    Springboot
    zookeeper 常用命令及znode简介
    Zookeeper 实现分布式锁服务
    Golang 基础
    ipython notebook 如何修改一开始打开的文件夹路径
    Loadrunner11配置Jdk,以及是否成功配置验证
    Redis学习
  • 原文地址:https://www.cnblogs.com/yudishow/p/5020145.html
Copyright © 2011-2022 走看看