记录一个抛物线

https://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/

文件:parabola.js

借鉴网上的抛物线写了个添加购物车的动画

<style>
    * {
        margin: 0;
        padding: 0;
    }

    .item {
        display: flex;
    }

    .item img {
        width: 200px;
        height: 200px;
    }

    .shopping-cart {
        position: fixed;
        bottom: 0;
        right: 0;
        width: 50px;
        height: 50px;
        background: red;
    }
</style>
<body>
    <div class="item">
        <img src="https://vncdn.mobi88.cn/20220107/ct/ah_srl/iamges/shareImg.png" alt="">

        <div class="add-to-cart">添加购物车</div>
    </div>
    <!-- 购物车图标 -->
    <div class="shopping-cart"></div>
</body>
<script>
    /* 
        封装一个通过dom节点名称筛选出指定dom的方法
        dom: 一个dom节点
        nodeName: string,需要返回的节点名称
    */
    function divFind(dom, nodeName) {
        var arr = dom.children
        var filterDom = ''
        if (arr.length <= 0) return dom;
        for (var i = 0; i < arr.length; i++) {
            console.log(arr[i].nodeName);
            if (arr[i].nodeName === String(nodeName).toUpperCase()) {
                filterDom = arr[i]
            }
        }
        return filterDom
    }

    // 设置样式
    function setCss(dom, cssName, cssStr) {
        dom.style[cssName] = String(cssStr)
    }

    // 防抖标识
    var disabled = false

    function animaStar() {
        // 设置防抖,动画中将不能触发
        if (disabled) return;
        disabled = true

        var itemDom = document.querySelector('.item')
        // 商品图片dom
        var currentImg = divFind(itemDom, 'img')
        // 购物车dom
        var cardDom = document.querySelector('.shopping-cart')

        if (!currentImg) return console.log('为获取到商品图片');
        // 注意克隆是否克隆子节点问题
        var imgCloneDom = currentImg.cloneNode()

        // 获取商品图片和终点dom信息
        var imgDomInfo = currentImg.getBoundingClientRect()
        var cardDomInfo = cardDom.getBoundingClientRect()

        // 设置样式
        setCss(imgCloneDom, 'width', currentImg.width + 'px')
        setCss(imgCloneDom, 'height', currentImg.height + 'px')
        setCss(imgCloneDom, 'position', 'fixed')
        setCss(imgCloneDom, 'top', imgDomInfo.top + 'px')
        setCss(imgCloneDom, 'left', imgDomInfo.left + 'px')
        setCss(imgCloneDom, 'z-index', '100')
        setCss(imgCloneDom, 'overflow', 'hidden')

        // 添加到页面
        document.body.appendChild(imgCloneDom)

        // 给动画的dom添加类标识
        imgCloneDom.classList.add('clone')

        // 开始动画
        anime({
            targets: imgCloneDom,
            keyframes: [
                {
                    'borderRadius': '50%',
                    'width': '50px',
                    'height': '50px',
                    'top': imgDomInfo.height / 2 - 25 + 'px',
                    'left': imgDomInfo.width / 2 - 25 + 'px',
                },
                // {
                //     translateX: 15,
                //     translateY: -15,
                // },
                // {
                //     top: cardDomInfo.top,
                //     left: cardDomInfo.left,
                //     translateX: 0,
                //     translateY: 0,
                // }
            ],
            changeComplete: function (anim) {
                startAnit()
            },
        });

        function startAnit() {
            // 获取初始元素到目标元素的偏移总量
            let diffX = cardDomInfo.left - imgDomInfo.left
            let diffY = cardDomInfo.top - imgDomInfo.top

            // 假设(elX,elY)为(0,0),则c = 0,求a、b
            // 设a=0.001 => 实际指焦点到准线的距离,可以抽象成曲率,这里模拟扔物体的抛物线,因此是开口向下的
            let a = 0.005

            // 则 b = (y - a*x*x) / x
            let b = (diffY - a * diffX * diffX) / diffX

            // 定义一个定时器,用来执行抛物线动画
            let timer = null;

            // 执行的时间
            let duration = 500

            function start() {
                // 执行的开始时间
                beginTime = new Date()
                // 结束的时间
                endTime = +beginTime + duration
                // 定时器,执行抛物线动画
                timer = setInterval(() => {
                    let now = new Date()
                    step(now);
                }, 13);
            }
            start()

            // 抛物线动画的方法
            function step(now) {
                let x, y;
                if (now > endTime) {
                    // 运行结束
                    x = diffX;
                    y = diffY;
                    clearInterval(timer);
                } else {
                    // 计算每一步的X轴的位置
                    x = diffX * ((now - beginTime) / duration);
                    // 则每一步的Y轴的位置y = a*x*x + b*x + c;   c==0;
                    y = a * x * x + b * x;
                }

                anime({
                    targets: imgCloneDom,
                    keyframes: [
                        {
                            left: imgDomInfo.left + x,
                            top: imgDomInfo.top + y,
                        },
                        {
                            scale: 0,
                        }
                    ],
                    endDelay: 200,
                    // easing: 'easeInOutExpo',
                    complete: function (anim) {
                        // console.log(anim);
                        // 动画结束,检测document中是否存在动画的dom
                        var cloneDom = document.getElementsByClassName('clone');
                        if (cloneDom.length > 0) {
                            // 移除动画dom
                            document.body.removeChild(imgCloneDom)
                            setTimeout(function () {
                                // 解除防抖
                                disabled = false
                            }, 500)
                        }
                    },
                })
            }
        }
    }
    var addBtn = document.querySelector('.add-to-cart')
    addBtn.addEventListener('click', function () {
        animaStar();
    })

</script>

可以封装成一个添加方法哈,待更新…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值