javascript仿天貓加入購物車動畫效果

龍恩0707發表於2015-09-12

javascript仿天貓加入購物車動畫效果

  注意:首先需要宣告的是:程式碼原思路不是我寫的,是在網上找的這種效果,自己使用程式碼封裝了下而已;程式碼中都有註釋,我們最主要的是理解拋物線的思路及在工作中完成這樣的任務,最近需要做類似於天貓加入購物車動畫效果,所以就在網上搜尋了下,就看到類似的效果,就把程式碼截下來自己封裝了下~~

  如果想要了解拋物線的細節,我建議大家先 看下 張鑫旭 講解的拋物線的文章,再來看如下JS程式碼,可能理解更深點~~

http://www.zhangxinxu.com/wordpress/2013/12/javascript-js-%E5%85%83%E7%B4%A0-%E6%8A%9B%E7%89%A9%E7%BA%BF-%E8%BF%90%E5%8A%A8-%E5%8A%A8%E7%94%BB/

首先我們來理解的是: 既然是拋物運動,那麼 運動的元素肯定需要 "絕對定位";配置的引數有如下:(依賴於Jquery或者zepto.js

 配置項  含義
 el  需要運動的元素 {object | string}  預設為null 
 offset  運動的元素在 X軸,Y軸的偏移位置
 targetEl  終點目標元素 這時就會自動獲取該元素的left、top值,來表示移動元素在X,Y軸的偏移位置;設定了這個引數,offset將失效
 duration  運動時間,預設為500毫秒
 curvature  拋物線曲率,就是彎曲的程度,越接近於0越像直線,預設0.001
 callback  運動完成後執行的回撥函式
 autostart  是否自動開始運動,預設為false
 stepCallback  運動過程中執行的回撥函式,this指向該物件,接受x,y引數,分別表示X,Y軸的偏移位置。

 JSFiddler效果如下:

JS拋物線運動效果

下面是所有的JS程式碼:

/*
 * 實現拋物線函式 Parabola
 * 切記既然是拋物線運動,那麼運動的元素需要絕對定位
 * 具體瞭解拋物線 可以看張鑫旭的文章 
 * http://www.zhangxinxu.com/wordpress/2013/12/javascript-js-%E5%85%83%E7%B4%A0-%E6%8A%9B%E7%89%A9%E7%BA%BF-%E8%BF%90%E5%8A%A8-%E5%8A%A8%E7%94%BB/
 */
var Parabola = function(opts){
    this.init(opts);
};
Parabola.prototype = {
    constructor: Parabola,
    /*
     * @fileoverview 頁面初始化
     * @param opts {Object} 配置引數
     */
    init: function(opts){
        this.opts =  $.extend(defaultConfig, opts || {});
        // 如果沒有運動的元素 直接return
        if(!this.opts.el) {
            return;
        }
        // 取元素 及 left top
        this.$el = $(this.opts.el);
        this.$elLeft = this._toInteger(this.$el.css("left"));
        this.$elTop = this._toInteger(this.$el.css("top"));
        // 計算x軸,y軸的偏移量
        if(this.opts.targetEl) {
            this.diffX = this._toInteger($(this.opts.targetEl).css("left")) - this.$elLeft;
            this.diffY = this._toInteger($(this.opts.targetEl).css("top")) - this.$elTop;
        }else {
            this.diffX = this.opts.offset[0];
            this.diffY = this.opts.offset[1];
        }
        // 運動時間
        this.duration = this.opts.duration;
        // 拋物線曲率
        this.curvature = this.opts.curvature;
        
        // 計時器
        this.timerId = null;
        /*
         * 根據兩點座標以及曲率確定運動曲線函式(也就是確定a, b的值)
         * 公式: y = a*x*x + b*x + c;
         * 因為經過(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
         */
         this.b = (this.diffY - this.curvature * this.diffX * this.diffX) / this.diffX;

         // 是否自動運動
         if(this.opts.autostart) {
             this.start();
         }
    },
    /*
     * @fileoverview 開始
     */
    start: function(){
        // 開始運動
        var self = this;
        // 設定起始時間 和 結束時間
        this.begin = (new Date()).getTime();
        this.end = this.begin + this.duration;
        
        // 如果目標的距離為0的話 就什麼不做
        if(this.diffX === 0 && this.diffY === 0) {
            return;
        }
        if(!!this.timerId) {
            clearInterval(this.timerId);
            this.stop();
        }
        // 每幀(對於大部分螢幕)大約16~17毫秒。預設大小是166.67。也就是預設10px/ms
        this.timerId = setInterval(function(){
            var t = (new Date()).getTime();
            self.step(t);
        },16);
        return this;
    },
    /*
     * @fileoverview 執行每一步
     * @param {string} t 時間
     */
    step: function(t){
        var opts = this.opts;
        var x,
            y;
        // 如果當前執行的時間大於結束的時間
        if(t > this.end) {
            // 執行結束
            x = this.diffX;
            y = this.diffY;
            this.move(x,y);
            this.stop();
            // 結束後 回撥
            if(typeof opts.callback === 'function') {
                opts.callback.call(this);
            }
        }else {
            // 每一步x軸的位置
            x = this.diffX * ((t - this.begin) / this.duration);
            // 每一步y軸的位置 y = a * x *x + b*x + c; c = 0
            y = this.curvature * x * x + this.b * x;
            // 移動
            this.move(x,y);
            if(typeof opts.stepCallback === 'function') {
                opts.stepCallback.call(this,x,y);
            }
        }
        return this;
    },
    /*
     * @fileoverview 給元素定位
     * @param {x,y} x,y座標
     * @return this
     */
    move: function(x,y) {
        this.$el.css({
            "position":'absolute',
            "left": this.$elLeft + x + 'px',
            "top": this.$elTop + y + 'px'
        });
        return this;
    },
    /*
     * 獲取配置項
     * @param {object} options配置引數
     * @return {object} 返回配置引數項
     */
    getOptions: function(options){
        if(typeof options !== "object") {
            options = {};
        }
        options = $.extend(defaultConfig, options || {});
        return options;
    },
    /*
     * 設定options
     * @param options
     */
    setOptions: function(options) {
        this.reset();
        if(typeof options !== 'object') {
            options = {};
        }
        options = $.extend(this.opts,options);
        this.init(options);
        return this;
    },
    /*
     * 重置
     */
    reset: function(x,y) {
        this.stop();
        x = x ? x : 0;
        y = y ? y : 0;
        this.move(x,y);
        return this;
    },
    /*
     * 停止
     */
    stop: function(){
        if(!!this.timerId){
            clearInterval(this.timerId);
        }
        return this;
    },
    /*
     * 變成整數
     * isFinite() 函式用於檢查其引數是否是無窮大。
     */
    _toInteger: function(text){
        text = parseInt(text);
        return isFinite(text) ? text : 0;
    }
};
var defaultConfig = {
    //需要運動的元素 {object | string}
    el: null,

    // 運動的元素在 X軸,Y軸的偏移位置
    offset: [0,0],

    // 終點元素 
    targetEl: null,

    // 運動時間,預設為500毫秒
    duration: 500,

    // 拋物線曲率,就是彎曲的程度,越接近於0越像直線,預設0.001
    curvature: 0.01,
    
    // 運動後執行的回撥函式
    callback: null,

    // 是否自動開始運動,預設為false
    autostart: false,
    
    // 運動過程中執行的回撥函式,this指向該物件,接受x,y引數,分別表示X,Y軸的偏移位置。
    stepCallback: null
};

HTML程式碼如下:

<div class="btns" style="margin-top:20px">
    <a href="#" id="reset">重置</a>
    <a href="#" id="run">開始運動</a>
    <a href="#" id="stop">停止運動</a>
    <a href="#" id="setOptions">設定配置引數</a>
</div>
<div id="boll" class="boll"></div>
<div id="target" class="target"></div>

JS初始化如下方式:

var bool = new Parabola({
    el: "#boll",
    offset: [500, 100],
    duration: 500,
    curvature: 0.005,
    callback:function(){
        alert("完成後回撥")
    },
    stepCallback:function(x,y){
                
        $("<div>").appendTo("body").css({
            "position": "absolute",
            "top": this.$elTop + y + 'px',
            "left":this.$elLeft + x + 'px',
            "background-color":"#CDCDCD",
            "width":"5px",
            "height":"5px",
            "border-radius": "5px"
        });
                
    }
});
$("#reset").click(function (event) {
    event.preventDefault();
    bool.reset();
});
$("#run").click(function (event) {
    event.preventDefault();
    bool.start();
});
$("#stop").click(function (event) {
    event.preventDefault();
    bool.stop();
});
$("#setOptions").click(function (event) {
    event.preventDefault();
    bool.setOptions({
        targetEl: $("#target"),
        curvature: 0.001,
        duration: 1000
    });
});

JS原始碼下載

相關文章