JavaScript之实现交通灯、红绿灯、使用模块导入js、不使用定时器、使用JS动画、import、requestAnimationFrame、Math、ceil、querySelector

MENU

  • 效果
  • html
  • JavaScript
  • 解析
  • requestAnimationFrame


效果

JavaScript之实现交通灯、红绿灯、使用模块导入js、不使用定时器、使用JS动画、import、requestAnimationFrame、Math、ceil、querySelector_第1张图片


html

<div class="d_f fd_c ai_c">
    <div class="w_268 d_f jc_sb ai_c">
        <div id="idRed" class="w_68 h_68 radius_50_ bc_rgba_68_68_86_05">div>
        <div id="idYellow" class="w_68 h_68 radius_50_ bc_rgba_68_68_86_05">div>
        <div id="idGreen" class="w_68 h_68 radius_50_ bc_rgba_68_68_86_05">div>
    div>

    <div id="idTime" class="mt_10 fs_30 fw_700">0div>

    <div class="mt_10 w_168 d_f jc_sb">
        <button class="c_p" onclick="handleStart()">开始button>
        <button class="c_p" onclick="handleCease()">停止button>
    div>
div>

<script type="module">
    import { TrafficLight } from './index.js';

    let idTime = document.querySelector('#idTime'),
        idRed = document.querySelector('#idRed'),
        idYellow = document.querySelector('#idYellow'),
        idGreen = document.querySelector('#idGreen'),
        light = undefined,
        current = undefined;

    function raf() {
        window.animation = requestAnimationFrame(() => {
            raf();

            const current = light.getCurrentLight();

            idRed.style.backgroundColor = current.color === 'red' ? current.HColor.color : '';
            idYellow.style.backgroundColor = current.color === 'yellow' ? current.HColor.color : '';
            idGreen.style.backgroundColor = current.color === 'green' ? current.HColor.color : '';

            idTime.textContent = current.remain;
        });
    }

    window.handleStart = function () {
        light = new TrafficLight({
            red: 5,
            yellow: 3,
            green: 10,
            initial: 'red'
        });
        current = light.getCurrentLight();

        raf();
    }

    window.handleCease = function () {
        cancelAnimationFrame(window.animation);

        window.animation = undefined;
    }
script>

1、使用window是因为script标签使用了module类型,导致onclick的访问不在同一作用域上。
2、样式实现原子化,即每一个样式使用属性与值的方式定义类名。


JavaScript

export class TrafficLight {
    constructor(options) {
        const {
            red = 60,
            green = 60,
            yellow = 3,
            initial = 'green'
        } = options;

        this._colors = {
            red: {
                seconds: red,
                next: 'yellow',
                color: '#ff0000'
            },
            green: {
                seconds: green,
                next: 'yellow',
                color: '#008000'
            },
            yellow: {
                seconds: yellow,
                color: '#ffff00'
            }
        };

        this._switch(initial);
    }

    _switch(color) {
        this._currentColor = color;
        this._seconds = this._colors[color].seconds;
        this._time = Date.now();
    }
    _next() {
        if (this._currentColor === 'red') {
            this._colors.yellow.next = 'green';
        } else if (this._currentColor === 'green') {
            this._colors.yellow.next = 'red';
        }

        this._switch(this._colors[this._currentColor].next);
    }
    getCurrentLight() {
        // const remain = Math.floor(this._seconds - (Date.now() - this._time) / 1000);
        const remain = Math.ceil(this._seconds - (Date.now() - this._time) / 1000);

        if (remain <= 0) {
            this._next();

            return this.getCurrentLight();
        }
        
        return {
            color: this._currentColor,
            HColor: this._colors[this._currentColor],
            remain
        };
    }
}

解析

待完成…


requestAnimationFrame

MDN

window.requestAnimationFrame()告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
备注:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用requestAnimationFrame()。requestAnimationFrame()是一次性的。
当你准备更新在屏动画时你应该调用此方法。这将使浏览器在下一次重绘之前调用你传入给该方法的动画函数(即你的回调函数)。回调函数执行次数通常是每秒60次,但在大多数遵循W3C建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。为了提高性能和电池寿命,在大多数浏览器里,当requestAnimationFrame()运行在后台标签页或者隐藏的