手记

【备战春招】第6天 破解JavaScript高级玩法 第十三讲

课程名称:** 破解JavaScript高级玩法

课程章节: 动起来:计时器和JS动画

主讲老师: Cloud

课程内容:

今天学习的内容包括:

CSS的动画实现

课程收获:

13.1 心得:

setInterval

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
</head>
<style>
    .warp {
        position: relative;
        height: 100px;
        background: red;
    }
</style>

<body>
    setIntervale
    <div id="progress" class="warp" >0%</div>
    <button id="start">开始</button>
    <script>
        //同步耗时操作
        function syncSleep(duration) {
            const now = Date.now();
            while (now + duration > Date.now()) { }
        }

        var interval = null;
        var timeout = null;
        var curCount = 0;
        var timeLine = Date.now();
        var lastIntervalTime;

        function printTime(text, isInterval) {
            if (isInterval) {
                var intervalTime = lastIntervalTime ? Date.now() - lastIntervalTime : '第一次执行';
                console.log(text, "==时间线:", Date.now() - timeLine, "上一次间隔:", intervalTime);
                lastIntervalTime = Date.now();
            } else {
                console.log(text, "==时间线:", Date.now() - timeLine);
            }
        }

        function intervalFun(totalCount) {
            interval = setInterval(() => {
                printTime("执行interval", true);
                syncSleep(4000);
                printTime("执行interval完毕");
                curCount += 1;
                if (curCount > totalCount) {
                    window.clearInterval(interval);
                }
            }, 5000);
        }

        intervalFun(6);



        timeout = setTimeout(() => {
            printTime("模拟click");
            start.click();
        }, 3000),

        timeout = setTimeout(() => {
            printTime("执行timeout");
            syncSleep(9000);
            printTime("执行timeout完毕");
        }, 4000),

        start.onclick = function () {
                printTime("执行onClick");
                syncSleep(6000);
                printTime("执行onClick完毕");
        };

        window.onbeforeunload = function (event) {
            console.log("卸载")
            if (timeout) {
                clearTimeout(timeout);
            }

            if (interval) {
                clearInterval(interval);
            }
        };

        //onclick(当前)                             3s + 6 
        //onclick(当前),timeout                     4s 
        //onclick(当前),timeout,interval-1         5s 
        //timeout(当前),interval-1                  9s + 9 
        //timeout(当前),interval-1                  10s     interval-2 
        //timeout(当前),interval-1                  15s     interval-3 
        //interval-1(当前)                          18s + 4 
        //interval-1(当前)                          18s + 4 
        //interval-1(当前),interval-4               20s 
        //interval-4(当前)                          22s + 4
        //interval-4(当前),interval-5              25s
        //interval-5(当前),                         26s + 4
        //interval-6                                 30s
        //interval-7                                 35s
    </script>
</body>

</html>

requestAnimationFrame

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .animate-ele {
        position: relative;
        width: 100px;
        height: 100px;
        background: red;
    }
    * {
        font-size: 28px;
    }
</style>

<body>
    <div id="animateEle" class="animate-ele"></div>
    <button id="start">开始</button>
    <script>

        const element = document.getElementById('animateEle');
        let count=0;
        function step() {
            count++;
           
            if(count<500){
                element.style.transform = 'translateX(' + count + 'px)';
                window.requestAnimationFrame(step);
            }
        }

        start.onclick=function(){
            window.requestAnimationFrame(step);
        }
       
    </script>
</body>

</html>

requestIdleCallback

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .animate-ele {
        position: relative;
        width: 100px;
        height: 100px;
        background: red;
    }
    * {
        font-size: 28px;
    }
</style>

<body>
    <div id="animateEle" class="animate-ele"></div>
    <button id="start">开始</button>
    <script>
        //同步耗时操作
        function syncSleep(duration) {
            const now = Date.now();
            while (now + duration > Date.now()) { }
        }

        const element = document.getElementById('animateEle');
        let count = 0;

        function step(timestamp) {
            console.log("渲染帧");
            count++;
            if (count < 500) {
                element.style.transform = 'translateX(' + count + 'px)';
                window.requestAnimationFrame(step);
            }
        }

        start.onclick = function () {
            console.log("启动帧");
            window.requestAnimationFrame(step);
            requestIdleCallback((idleDeadline) => {
                // didTimeout表示是否超时正在执行
                const didTimeout = idleDeadline.didTimeout ? '超时正在执行' : '未超时执行'
                // timeRemaining()表示当前帧还剩余多少时间(以毫秒计算)
                const timeRemaining = idleDeadline.timeRemaining();
                console.log("didTimeout==", didTimeout, "==", timeRemaining)

                // { timeout: 50 }
            }, {timeout: 50});//{timeout:50}

            console.log("执行onClick")
            setTimeout(() => {
                console.log("执行timeout")
                syncSleep(1000);
                console.log("执行timeout完成");
                Promise.resolve().then(function () {
                    console.log("promise 微任务");
                });
            }, 30)
            syncSleep(1000);
            console.log("执行onClick完毕")
        };

    </script>
</body>

</html>

基于传统定时器的动画实现

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    * {
        font-size: 28px;
        ;
    }

    .warp {
        position: absolute;
        width: 100px;
        height: 300px;
        border: 1px solid #F60093;
        overflow: hidden;
    }

    .progress-in {
        position: relative;
        width: 100%;
        height: 100%;
        background: red;
        animation: 3s linear 0s progress forwards;
        transform: translateY(100%);
        animation-play-state: paused;
    }

    @keyframes progress {
        from {
            transform: translateY(100%);
        }

        to {
            transform: translateY(0%);
        }
    }

    #start {
        position: absolute;
        width: 100px;
        left: 200px;
    }
</style>

<body>
    <div class="warp">
        <div class="progress-in">

        </div>
    </div>
    <button id="start">开始</button>
    <script>
        const progressIn = document.querySelector(".progress-in");
        start.onclick = function () {
            // progressIn.style.animationPlayState = `running`;
            const state = progressIn.style.animationPlayState;
            progressIn.style.animationPlayState = state == `running` ? "paused" : "running";
        }

        progressIn.addEventListener("webkitAnimationEnd", (ele) => {
            window.alert(`动画结束`);
        }, true);
    </script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .warp {
        position: absolute;
        width: 100px;
        height: 300px;
        border: 1px solid #F60093;
        overflow: hidden;
    }

    .progress-in {
        position: relative;
        width: 100%;
        height: 100%;
        background: red;
        opacity: 1;
        transform: translateY(100%);
        transition: transform 3s, opacity 3s;
    }

    #start {
        position: absolute;
        width: 100px;
        height: 30px;
        left: 200px;
    }
</style>

<body>
    <div class="warp">
        <div class="progress-in">

        </div>
    </div>
    <button id="start">开始</button>
    <script>

        const progressIn = document.querySelector(".progress-in");
        start.onclick = function () {
            progressIn.style.transform = `translateY(0%)`;
            progressIn.style.opacity = 0.4;
        }

        progressIn.addEventListener("transitionend", (ele) => {
            console.log(`过渡动画完成:过渡属性${ele.propertyName}=过渡时间:${ele.elapsedTime}s`);
        }, true);
    </script>
</body>

</html>

购物车抛物线

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>购物车抛物线</title>
    <style>
        html,
        body {
            margin: 0
        }

        body {
            position: relative;
        }

        .container {
            /* width: 30vw; */
            margin: auto;
            height: 94vh;
            background-color: #fff4e8;
            position: relative;
            padding-top: 50px;
        }

        .container section {
            display: flex;
            margin: 8px;
            max-width: 500px;
            margin: auto;
        }

        .container section div {
            align-self: center;
        }

        .container .add-car {
            background: #e54346;
            height: 30px;
            text-align: center;
            align-self: center;
        }

        .fixed-bottom {
            position: fixed;
            bottom: 0px;
            z-index: 999;
            width: 100vw;
            height: 6vh;
        }

        .bottom-wrapper {
            width: 30vw;
            margin: auto;
            border: silver solid 1px;
            position: relative;
            overflow: hidden;
        }

        .car {
            height: 5vh;
            margin-left: 10px;
        }

        .prod-img {
            border: 1px solid #eee;
        }

        .moving-point {
            height: 20px;
            position: absolute;
            display: none;
            transform: translate(-50%, -50%);
            z-index: 999;
        }

        @media screen and (max-width: 500px) {
            .container section{
                max-width: 100vw;
            }
        }
    </style>
</head>

<body>

    <div class="container">
        <section>
            <img class="prod-img"
                src="//img10.360buyimg.com/cms/s80x80_jfs/t18700/63/435443749/91471/d622467/5a780f67Nc9f4b35b.jpg">
            <div>花王碧柔(Biore)轻透倍护防晒乳SPF50+ PA+++ 40ml 轻透</div>
            <img src="./add.jpg" class="add-car" />
        </section>
        <section>
            <img class="prod-img"
                src="//img10.360buyimg.com/cms/s80x80_jfs/t18700/63/435443749/91471/d622467/5a780f67Nc9f4b35b.jpg">
            <div>花王碧柔(Biore)轻透倍护防晒乳SPF50+ PA+++ 40ml 轻透</div>
            <img src="./add.jpg" class="add-car" />
        </section>
        <section>
            <img class="prod-img"
                src="//img10.360buyimg.com/cms/s80x80_jfs/t18700/63/435443749/91471/d622467/5a780f67Nc9f4b35b.jpg">
            <div>花王碧柔(Biore)轻透倍护防晒乳SPF50+ PA+++ 40ml 轻透</div>
            <img src="./add.jpg" class="add-car" />
        </section>
        <section>
            <img class="prod-img"
                src="//img10.360buyimg.com/cms/s80x80_jfs/t18700/63/435443749/91471/d622467/5a780f67Nc9f4b35b.jpg">
            <div>花王碧柔(Biore)轻透倍护防晒乳SPF50+ PA+++ 40ml 轻透</div>
            <img src="./add.jpg" class="add-car" />
        </section>
        <section>
            <img class="prod-img"
                src="//img10.360buyimg.com/cms/s80x80_jfs/t18700/63/435443749/91471/d622467/5a780f67Nc9f4b35b.jpg">
            <div>花王碧柔(Biore)轻透倍护防晒乳SPF50+ PA+++ 40ml 轻透</div>
            <img src="./add.jpg" class="add-car" />
        </section>
        <section>
            <img class="prod-img"
                src="//img10.360buyimg.com/cms/s80x80_jfs/t18700/63/435443749/91471/d622467/5a780f67Nc9f4b35b.jpg">
            <div>花王碧柔(Biore)轻透倍护防晒乳SPF50+ PA+++ 40ml 轻透</div>
            <img src="./add.jpg" class="add-car" />
        </section>

    </div>

    <div class="fixed-bottom">
        <div class="bottom-wrapper">
            <img src="./car.jpg" alt="" class="car">
        </div>

    </div>

    <img src="./add.jpg" alt="" class="moving-point">

    <script>

        var animating = false;
        var carEl = document.querySelector(".car");
        var pointEl = document.querySelector(".moving-point");

        document.querySelector(".container").addEventListener("click", function (ev) {
            const el = ev.target;
            if (el.classList.contains("add-car")) {
                if (animating) {
                    return;
                }
                animating = true;
                reset();
                var sourcePos = {
                    x: ev.x,
                    y: ev.y
                };

                pointEl.style.top = numberToPx(sourcePos.y);
                pointEl.style.left = numberToPx(sourcePos.x);
                pointEl.style.display = "block";

                window.getComputedStyle(document.body);

                requestAnimationFrame(transition)
            }
        })


        function reset() {
            pointEl.style.transition = "";
        }

        function transition() {
            var targetPos = getTargetPos();

            pointEl.style.transition = `top 500ms ease-in,left 500ms linear`;
            pointEl.style.top = numberToPx(targetPos.y);
            pointEl.style.left = numberToPx(targetPos.x);
        }


        function numberToPx(n) {
            return n + "px";
        }


        function getTargetPos() {
            var pos = carEl.getBoundingClientRect();
            return {
                x: pos.x + pos.width / 2,
                y: pos.y + pos.height / 2
            }
        }

        pointEl.addEventListener("transitionend", function () {
            animating = false;
            pointEl.style.transition = "";
            pointEl.style.display = "none";
        })


    </script>

</body>

</html>

内置贝塞尔的运动

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>内置贝塞尔的运动</title>
    <style>
        
        *  {
            font-size: 28px;
            color: #FFF;
            font-weight: bold
        }

        .bg-red {
            background-color: red;
        }

        .bg-green {
            background-color: green;
        }

        .bg-blue {
            background-color: blue;
        }


        .bg-sliver {
            background-color: silver;
        }

        .bg-aqua {
            background-color: aqua
        }

        .transition div {
            height: 100px;
            width: 100px;
            position: relative;
            left: 0;
        }

        .transition-s {
            transition-property: left;
            transition-duration: 3000ms;
        }

        .transition-fn-ease {
            transition-timing-function: ease;
        }

        .transition-fn-ease-in {
            transition-timing-function: ease-in;
        }

        .transition-fn-linear {
            transition-timing-function: linear;
        }

        .transition-fn-ease-out {
            transition-timing-function: ease-out;
        }

        .transition-fn-ease-in-out {
            transition-timing-function: ease-in-out;
            
             /* transition-timing-function: cubic-bezier(.95,.05,.59,.75) */
        }

        .transition.ani div{
            left: calc(100% - 100px);
        }
    </style>
</head>

<body>

    <div class="transition">
        <div class="bg-red transition-s transition-fn-ease" data-t="ease">ease</div>
        <div class="bg-green transition-s transition-fn-linear" data-t="linear">linear</div>
        <div class="bg-blue transition-s transition-fn-ease-in" data-t="ease-in">ease-in</div>
        <div class="bg-sliver transition-s transition-fn-ease-out" data-t="ease-out">ease-out</div>
        <div class="bg-aqua transition-s transition-fn-ease-in-out" data-t="ease-in-out">ease-in-out</div>
    </div>
    <div>
    <button id="btnStart" >开始</button>
    </div>

    <script>

        var el = document.querySelector(".transition");
        document.getElementById("btnStart").addEventListener("click", function(){
            el.classList.add("ani");
        })

        document.querySelector(".transition-s").addEventListener("transitionend", function(){
            el.classList.remove("ani");
        })



    </script>

</body>

</html>

进度条

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>加载进度条</title>
    <style>
        html,
        body {
            height: 100%;
            cursor: pointer;
        }
        body {
            padding-top: 100px;
            background-color: rgba(0, 0, 0)
        }
        .outer {
            margin: auto;
            width: 90%;
            height: 10px;
            border-radius: 8px;
            background-color : #000;
            border-left: 2px solid rgba(0, 198, 255, .3);
            border-top: 2px solid rgba(0, 198, 255, .3);
            border-right: 2px solid rgba(0, 198, 255, .3);
            border-bottom: 2px solid rgba(0, 198, 255, .3);
        }
        .inner {
            height: 10px;
            box-shadow: 0px 0px 10px rgba(0, 198, 255, 1) inset;
            width: 0;
            border-radius: 8px;
        }

        .ts {
            transition: width 5000ms ease 20ms;
        }

        .title {
            text-align: center;
            margin: 10px;
            color: #fff;
        }

        .progress {
            width: 100%;
        }
    </style>
</head>


<body>

    <div class="title">
        来来来, 点击任何地方开始加载
    </div>
    <div class="outer">
        <div class="inner"></div>
    </div>


    <script>

        var innerEl = document.querySelector(".inner");
        function reset() {
            innerEl.classList.remove("progress");
            innerEl.classList.remove("ts");

        }
        document.body.addEventListener("click", function () {
            reset();
            window.getComputedStyle(document.body);
            requestAnimationFrame(function () {
                innerEl.classList.add("ts");
                if (!innerEl.classList.contains("progress")) {
                    innerEl.classList.add("progress");
                }
            })
        })

    </script>

</body>

</html>

雪花飘飘

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Snow</title>
    <style>
        body {
            background-color: black;
            overflow: hidden;
            height: 100vh;
            cursor: pointer;
        }

        .ts {
            transition-property: all;
            transition-timing-function: ease;
        }


        img {
            height: 15px;
            position: absolute;
            top: 0;
            left: 50vw;
            transform: translate(-50%);
        }
    </style>
</head>

<body>
</body>
<script>

    var animating = false;
    var created = false;
    function createSnows() {
        if (created) {
            return
        }
        for (var i = 0; i < 800; i++) {
            var img = document.createElement("img");
            img.src = "./snow.png";
            img.className = "ts";

            var w = (10 + Math.round(Math.random() * 30)) + "px";
            img.style.width = w;
            img.style.height = w;
            document.body.appendChild(img)
        }
        created = true;
    }

    function updateSnows() {
        [...document.images].forEach(function (el, i) {
            el.classList.add("ts");
            el.style.transitionDuration = 3000 + Math.floor(Math.random() * i * 1000/800 ) + "ms";
            el.style.left = 50 + (Math.random() > 0.49 ? 1 : -1) * Math.random() * 200 + "vw";
            el.style.top = 100 + 1 * Math.round(Math.random() * 50) + "vh";
            el.style.transitionTimingFunction = `cubic-bezier(${Math.random().toFixed(2)},${Math.random().toFixed(2)},${Math.random().toFixed(2)},${Math.random().toFixed(2)})`
        })
    }

    function resetSnows() {
        [...document.images].forEach(function (el, i) {
            el.style.transition = "";
            el.style.top = "0";
            el.style.left = "50vw";
            el.classList.remove("ts");
        })
    }

    createSnows();

    document.body.addEventListener("click", function () {
        resetSnows();
        window.getComputedStyle(document.body);
        requestAnimationFrame(updateSnows)
    })


</script>

</html>

0人推荐
随时随地看视频
慕课网APP