仿钉钉特效

看网上的视频说到仿钉钉特效,又查阅到css相关的知识,尝试用css动画实现钉钉动效(需要一点js代码,如果使用scss则只需要监听滚动)代码如下

<style>
    :root {
        --nums: 16;
        --boxLength: 50px;
        --boxMargin: 18px;
    }

    #main {
        width: 100%;
        height: 3000px;
        display: flex;
    }

    #container {
        height: 600px;
        width: calc(var(--nums) / 2 * (var(--boxMargin) + var(--boxLength)));
        margin: auto;

    }

    #scroll {
        position: sticky;
        top: calc(50vh - 0.5 * (var(--boxLength) + var(--boxMargin)));
        display: flex;
        flex-wrap: wrap;
    }

    #scroll > div:nth-of-type(n) {
        margin-right: var(--boxMargin);
        margin-bottom: var(--boxMargin);
        width: var(--boxLength);
        height: var(--boxLength);
    }
</style>
<div id="main">
    <div id="container">
        <div id="scroll">
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </div>
    </div>
</div>
<script>
    const doms = {
        boxes: document.getElementById('scroll').children,
        scroll: document.getElementById('scroll'),
        main: document.getElementById('main'),
        container: document.getElementById('container')
    }
    const pos = {
        begin: doms.container.offsetTop,
        end: doms.container.offsetTop + doms.container.offsetHeight - doms.scroll.offsetHeight
    }
    console.dir(doms.scroll)
    const animationCreator = (begin, end, attrBegin, attrEnd) => {//起始位置 结束位置 属性的起始 结束
        const all = end - begin
        const attrAll = attrEnd - attrBegin
        //该函数返回一个函数,传入当前的运动到的位置。返回一个动画的进度节点
        return (pos) => {
            const use = pos - begin
            const percent = (use / all).toFixed(2)
            const attrFinished = attrBegin + attrAll * percent
            return attrFinished.toFixed(2)
        }
    };
    const keyFrame = (index) => {
        const boxLeftTop = [doms.boxes[index].offsetLeft, doms.boxes[index].offsetTop]
        const middlePos = [doms.boxes[12].offsetLeft - 25, doms.boxes[12].offsetTop - 25]
        return `@keyframes move-${index}{
            0% {
               transform:translate(${middlePos[0] - boxLeftTop[0]}px,${middlePos[1] - boxLeftTop[1]}px)//动画开始时把所有的方块移动到中心点
            }
            100%{
               transform: translate(0px, 0px);//动画结束时回到原点
            }
        }`
    }
    const style = document.createElement('style')
    for (let i = 0; i < doms.boxes.length; i++) {
        style.innerHTML += keyFrame(i)
        doms.boxes[i].style.backgroundColor = `hsl(${Math.random() * 360},50%,50%)`
    }
    document.getElementsByTagName('head')[0].appendChild(style);
    const opacityAnimation = animationCreator(pos.begin, pos.end, 0, 100)//生成透明度变化的动画进度
    const moveAnimation = animationCreator(pos.begin, pos.end, 0, 1)//生成css动画 delay进度
    addEventListener('scroll', (e) => {
        const target = doms.scroll.offsetTop
        if (target > pos.begin && target < pos.end) {
            for (let i = 0; i < doms.boxes.length; i++) {
                doms.boxes[i].style.opacity = opacityAnimation(target) + '%'
                doms.boxes[i].style.animation = `move-${i} 1s ${-moveAnimation(target)}s paused` //暂停动画,根据delay控制物体的位置。不需要计算每次滑动后所到达的位置,只需要给出初始位置和结束位置,计算delay值即可
            }
        }
        if (target >= pos.end) {
            for (let i = 0; i < doms.boxes.length; i++) {
                doms.boxes[i].style.opacity = '1'
                doms.boxes[i].style.animation = ''
            }

        }
        if (target <= pos.begin) {
            for (let i = 0; i < doms.boxes.length; i++) {
                doms.boxes[i].style.opacity = 0
                doms.boxes[i].style.animation = ''
            }
        }
    })


</script>

生成一个粘性布局,外面包一层大的壳用来控制滑动到特定区域悬停,用js计算滑动的初始范围和结束范围,由此可以根据滑动的进度生成动画的进度。具体实现可以看代码注释

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值