动画基础知识(33)

动画的基础知识

 * 动画

 *   1.CSS3动画(能用C3解决的动画绝对不用JS,因为C3动画性能好)

 *    + transition过渡动画

  *   + animation帧动画

  *   + transform是变形不是动画(经常依托某一种动画让元素在一定时间内实现变形效果)

  *

  *  2.JS动画

  *   + 定时器

  *   + requestAnimationFrame(JS中的帧动画)

  *   + 所谓的canvas动画就是JS基于定时器完成(canvas是一个HTML标签,可以理解为是一个画布,我们可以基于JS在画布上绘制出图像和效果)

  *

  *  3.FLASH动画(ActionScript)

//=>需求:让BOX盒子从最左边运动到最右边(结束) [修改BOX的LEFT值即可]
let minL = 0,
    maxL = document.documentElement.clientWidth - box.offsetWidth;

//=>[固定步长的匀速运动]
let step = 5,
    autoTimer = setInterval(() => {
        let curL = box.offsetLeft;//=>我们用左偏移临时代替一下LEFT值
        curL += step;
        if (curL >= maxL) {
            //=>固定步长的情况下做边界判断:都是先加上步长在做判断,验证我如果走这一步会不会超,如果超了,我们直接运动到末尾即可,没超才走一步
            box.style.left = maxL + 'px';
            clearInterval(autoTimer);
            return;
        }
        box.style.left = curL + 'px';
    }, 17);//=>17/13MS都是比较好的动画执行时间(浏览器不会出现卡顿)

//=>[固定时间的匀速运动]
let duration = 1000,//=>总时间
    interval = 17,//=>频率:多长时间迈一步
    begin = 0,//=>起始位置
    target = maxL,//=>目标位置
    change = target - begin,//=>总距离:目标值(TARGET)-起始值(BEGIN)
    time = 0;//=>已经运动的时间
let autoTimer = setInterval(() => {
    //=>根据公式计算出当前盒子应有的位置
    time += interval;//=>time+=17;
    if (time >= duration) {
        //=>当前运动的时间超过总时间:到达边界
        box.style.left = target + 'px';
        clearInterval(autoTimer);
        return;
    }
    let curL = time / duration * change + begin;
    box.style.left = curL + 'px';
}, interval);


//1.第一种思路:步长=总距离/总时间*频率,剩下变为固定步长的匀速运动了
//2.在JS中基于定时器完成动画,不论是固定步长还是固定时间,只要算出当前盒子应该运动的位置即可(新的位置信息)

//t:TIME当前运动的时间
//d:DURATION总时间
//b:BEGIN起始位置
//c:CHANGE总距离 (TARGET-BEGIN)
// t/d:当前已经运动的时间/总时间 =>当前动画完成的百分比
// t/d*c:当前动画完成的百分比*总距离 =>当前已经走的距离
// t/d*c+b:当前走的距离+盒子的起始位置 =>当前盒子应该有的位置

规定时间内的多方向匀速运动

/*
 * 规定时间内的多方向匀速运动
 *    TIME 当前运动时间
 *    DURATION 总时间
 *
 *    [记录每一个方向的起始位置、目标值、总距离]
 *      BEGIN 起始位置
 *      TARGET 目标位置
 *      CHANGE 总距离
 */
let time = 0,
    duration = 1000;
let target = {
    left: document.documentElement.clientWidth - box.offsetWidth,
    top: document.documentElement.clientHeight - box.offsetHeight,
    width: 50,
    height: 50,
    fontSize: 30
};
// let change = {
//     left: target['left'] - begin['left'],
//     top: target['top'] - begin['top']
// };

//=>根据目标值计算出当前元素每一个运动方向的总距离(前提:计算出每个方向的起始值)
let change = {};
let begin = {};
for (let attr in target) {
    if (target.hasOwnProperty(attr)) {
        begin[attr] = parseFloat(window.getComputedStyle(box)[attr]);
        change[attr] = target[attr] - begin[attr];
    }
}

let animateTimer = setInterval(() => {
    time += 17;
    if (time >= duration) {
        clearInterval(animateTimer);
        for (let key in target) {
            if (target.hasOwnProperty(key)) {
                box.style[key] = target[key] + 'px';
            }
        }
        return;
    }
    //=>根据目标值中的方向,基于公式计算出每一个方向的当前位置
    let cur = {};
    for (let attr in target) {
        if (target.hasOwnProperty(attr)) {
            cur[attr] = time / duration * change[attr] + begin[attr];
        }
    }
    for (let key in cur) {
        if (cur.hasOwnProperty(key)) {
            box.style[key] = cur[key] + 'px';
        }
    }
}, 17);

封装基础版动画库

/*==ANIMATE动画库==*/
~function () {
    //=>准备操作CSS样式的方法 GET-CSS/SET-CSS/SET-GROUP-CSS/CSS
    let utils = (function () {
        //=>获取样式
        let getCss = (ele, attr) => {
            let val = null,
                reg = /^-?\d+(\.\d+)?(px|rem|em)?$/;
            if ('getComputedStyle' in window) {
                val = window.getComputedStyle(ele)[attr];
                if (reg.test(val)) {
                    val = parseFloat(val);
                }
            }
            return val;
        };

        //=>设置样式
        let setCss = (ele, attr, value) => {
            if (!isNaN(value)) {
                if (!/^(opacity|zIndex)$/.test(attr)) {
                    value += 'px';
                }
            }
            ele['style'][attr] = value;
        };

        //=>批量设置样式
        let setGroupCss = (ele, options) => {
            for (let attr in options) {
                if (options.hasOwnProperty(attr)) {
                    setCss(ele, attr, options[attr]);
                }
            }
        };

        //=>合并为一个
        let css = (...arg) => {
            let len = arg.length,
                fn = getCss;
            if (len >= 3) {
                fn = setCss;
            }
            if (len === 2 && typeof arg[1] === 'object') {
                fn = setGroupCss;
            }
            return fn(...arg);
        };

        return {css}
    })();

    //=>EFFECT:准备运动的公式
    let effect = {
        Linear: (t, b, c, d) => t / d * c + b
    };

    //=>封装动画库
    window.animate = function (ele, target = {}, duration = 1000, callback = new Function()) {
        //=>不传递CALL-BACK,让其默认为一个空函数(回调函数:当动画结束后做什么事,都放到回调函数完成即可)
        if (typeof duration === 'function') {
            //=>我们有四个形参,但是传递的时候只传递三个,最后一个回调函数传递给duration这个参数了,我们需要改一下参数的值
            callback = duration;
            duration = 1000;
        }

        //1.基于TARGET计算出BEGIN/CHANGE
        let begin = {},
            change = {},
            time = 0;
        for (let attr in target) {
            if (target.hasOwnProperty(attr)) {
                begin[attr] = utils.css(ele, attr);
                change[attr] = target[attr] - begin[attr];
            }
        }

        //2.实现动画
        clearInterval(ele.animteTimer);//=>在给当前元素设置新的动画之前,先清空原有正在运行的动画(防止多动画共存,把动画的返回值赋值给当前元素的自定义属性,这样只要元素不变,我们不管啥时候在哪执行都可以清除元素的动画)
        ele.animteTimer = setInterval(() => {
            time += 17;
            //=>边界判断
            if (time >= duration) {
                utils.css(ele, target);
                clearInterval(ele.animteTimer);

                callback.call(ele);//=>动画完成后执行CALL-BACK(并且让回调函数中的THIS是当前操作的元素本身)
                return;
            }
            //=>依托TARGET计算出每个方向的当前位置
            let cur = {};
            for (let attr in target) {
                if (target.hasOwnProperty(attr)) {
                    cur[attr] = effect.Linear(time, begin[attr], change[attr], duration);
                }
            }
            utils.css(ele, cur);
        }, 17);
    };
}();

animate(box, {
    top: 0,
    left: 0
}, function () {
    //=>this:box
    this.style.borderRadius = '50%';
    this.style.backgroundColor = 'green';
});

 JQ中的动画方法

let $box = $('#box');
//=>animate:$.prototype
//EFFECT:linear\ease\ease-in\ease-out\ease-in-out

//=>stop:结束正在运行的动画,继续执行下一个新的动画
//=>finish:同stop一样也是结束正在运行的动画(结束动画后让元素立即运动到目标位置,从上一个动画的目标位置作为下一个动画的起始位置,stop是从哪停止的,就从哪开始)
// $box.stop().animate({
//     top: 300,
//     left: 500
// }, 500, () => {
//     $box.css({
//         borderRadius: '50%',
//         background: 'lightblue'
//     });
// });

// $box.animate({
//     top: 0,
//     left: 0
// }, 5000);
// setTimeout(() => {
//     $box.finish();
//     //$box.finish();
// }, 1000);

//=>快捷动画
//1. show/hide/toggle
//2. fadeIn/fadeOut/fadeToggle
//3. slideDown/slideUp/slideToggle
// 可以指定具体运动时间,也可以指定'slow' / 'fast'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值