Дисплей оставшееся время в данное время


Контексте

Эта программа представляет собой таймер обратного отсчета/визуальный таймер. Первоначально она была разработана для отображения времени, оставшегося до конца экзамена.


Вопрос

Мой JavaScript-это работает, но когда я хочу проверить некоторые код качественный инструмент, он продолжает преподносить мне эту ошибку: SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode.

Если вы можете улучшить этот код и помочь мне улучшить его(даже дизайн), буду очень благодарна.

Вот код:

'use strict'
 
const load = () => {
    const data = {}
 
    init(data)
 
    setInterval(() => {
        update(data)
        render(data)
    }, 100)
 
    document.querySelector('#start').onclick = event => {
        start(data)
    }
 
    document.querySelector('#reset').onclick = event => {
        reset(data)
    }
 
    document.querySelector('#license').onclick = showLicense
}
 
const init = data => {
    data.canvas = document.querySelector('#countdown')
    data.ctx = data.canvas.getContext('2d')
 
    data.endTime = Date.now()
    data.start = false
    data.reset = false
 
    data.canvas.width = data.canvas.height = 500
}
 
const update = data => {
    if (data.start || data.reset) {
        data.startAngle = timeToAngle(data.endTime)
        data.reset = false
    }
    if (data.start) {
        let difference = Math.abs(Math.floor((data.endTime - Date.now()) / 1000))
        let seconds = pad(difference % 60, '00')
        difference = Math.floor(difference / 60)
        let minutes = pad(difference % 60, '00')
        difference = Math.floor(difference / 60)
        let hours = difference
 
        if (data.endTime < Date.now()) {
            if (hours != 0) {
                hours = -hours
            } else if (minutes != 0) {
                minutes = -minutes
            } else {
                seconds = -seconds
            }
        }
 
        document.querySelector('#hours').value = hours
        document.querySelector('#minutes').value = minutes
        document.querySelector('#seconds').value = seconds
    }
}
 
const render = data => {
    const {
        canvas,
        ctx,
        startAngle,
        start
    } = data
 
    ctx.fillStyle = '#fff'
    ctx.fillRect(0, 0, canvas.width, canvas.height)
 
    let angle = Math.abs(startAngle)
 
    ctx.save()
 
    if (startAngle > 0) {
        ctx.translate(canvas.width / 2, canvas.height / 2)
        ctx.rotate(-Math.PI / 2)
        ctx.scale(1, -1)
        ctx.translate(-canvas.width / 2, -canvas.height / 2)
        ctx.fillStyle = 'rgba(0, 0, 255, 0.5)'
    } else {
        ctx.translate(canvas.width / 2, canvas.height / 2)
        ctx.rotate(-Math.PI / 2)
        ctx.translate(-canvas.width / 2, -canvas.height / 2)
        ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'
    }
 
    while (angle > 2 * Math.PI) {
        ctx.beginPath()
        ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI)
        ctx.fill()
 
        angle -= 2 * Math.PI
    }
 
    ctx.beginPath()
    ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle)
    ctx.lineTo(canvas.width / 2, canvas.height / 2)
    ctx.fill()
 
    ctx.restore()
}
 
const start = data => {
    const button = document.querySelector('#start')
    if (data.start) {
        button.innerText = 'Start'
    } else {
        let hours = document.querySelector('#hours').value
        let minutes = document.querySelector('#minutes').value
        let seconds = document.querySelector('#seconds').value
        if (hours.trim() == '') hours = 0
        if (minutes.trim() == '') minutes = 0
        if (seconds.trim() == '') seconds = 0
 
        let sign
        if (hours != 0) {
            sign = hours < 0 ? -1 : 1
        } else if (minutes != 0) {
            sign = minutes < 0 ? -1 : 1
        } else {
            sign = seconds < 0 ? -1 : 1
        }
 
        minutes = sign * Math.abs(minutes)
        seconds = sign * Math.abs(seconds)
 
        data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds
 
        button.innerText = 'Pause'
    }
    data.start ^= true
}
 
const reset = data => {
    data.endTime = Date.now()
    data.start = false
    document.querySelector('#hours').value = ''
    document.querySelector('#minutes').value = ''
    document.querySelector('#seconds').value = ''
    document.querySelector('#start').innerText = 'Start'
    data.reset = true
}
 
const showLicense = () => {
    const mask = document.createElement('div')
    mask.style = 'position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0, 0, 0, 0.5);z-index:1;'
    mask.onclick = () => {
        document.body.removeChild(mask)
        document.body.removeChild(message)
    }
    document.body.appendChild(mask)
 
    const message = document.createElement('div')
    message.style = 'position:fixed;left:50%;top:50%;transform:translate(-50%, -50%);z-index:2;background:#fff;padding:10px;border-radius:10px;overflow:auto;max-width:600px;max-height:500px;'
    message.innerText = 'License unavailable, please report as a bug.'
    message.onclick = () => {
        document.body.removeChild(mask)
        document.body.removeChild(message)
    }
 
    const ajax = new XMLHttpRequest()
    ajax.open('GET', 'LICENSE')
    ajax.onreadystatechange = () => {
        console.log('AJAX');
        message.innerText = ajax.responseText
    }
    ajax.send()
    document.body.append(message)
}
 
const timeToAngle = endTime => {
    const difference = endTime - Date.now()
    return difference / 3600000 * 2 * Math.PI
}
 
const pad = (value, format) => (format + value).slice(-format.length)
 
load()
* {
    box-sizing: border-box;
}

body {
    background: #eee;
    margin: 0;
}

main {
    background: #fff;
    max-width: 700px;
    margin: auto;
    padding: 10px;
    display: flex;
    flex-flow: column;
    align-items: center;
}

h1 {
    text-align: center;
}

menu {
    display: flex;
    justify-content: space-between;
    width: 500px;
    padding: 0;
}

#hours, #minutes, #seconds {
    width: 30px;
    text-align: center;
}

footer {
    max-width: 700px;
    margin: auto;
    background: #ddd;
    padding: 10px;
    display: flex;
    justify-content: space-between;
}

footer a {
    display: inline-block;
    background: #ccc;
    padding: 10px;
    border-radius: 10px;
    color: black;
    text-decoration: none;
    cursor: pointer;
}

footer a:hover {
    background: #888;
    color: #fff;
}
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Countdown</title>
    <script src="countdown.js" defer></script>
    <link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>
    <main>
        <h1 contenteditable>Countdown</h1>
        <canvas id="countdown"></canvas>
        <menu>
            <button id="reset">Reset</button>
            <div class="group">
                <input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
            </div>
            <button id="start">Start</button>
        </menu>
    </main>
    <footer>
        <a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
        <a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
        <a id="license">MIT license</a>
    </footer>
</body>

</html>



157
2
задан 22 марта 2018 в 04:03 Источник Поделиться
Комментарии
2 ответа

Вы передаете вашего приложения в качестве параметра data практически все функции.

Это говорит о тебе лучше совмещать эти функции в класс, где вы могли бы присвоить эти значения this который будет автоматически доступна из всех методов в классе.

Кроме того, если все это является крошечной приложение, вы могли бы просто использовать глобальные переменные, которые тоже будут доступны все функции.

2
ответ дан 5 мая 2018 в 11:05 Источник Поделиться

Точки обзора


  • Выборка DOM-элементов не дешевая, поэтому кэш тех в переменной (возможно, в data) вместо того, чтобы пользоваться им каждый раз.

  • Когда выборка DOM-элементов с помощью атрибута id, используйте document.getElementById() вместо document.querySelector('#') посмотрите ответы на этот вопрос так и соответствующими см. Этот тест jsperf тест

  • Событие делегат может уменьшить количество щелкните обработчики нужны - пример приведенный ниже фрагмент использования функции.помощью bind() , чтобы создать частично примененные функции для простого делегата событий - если вы не используете событие делегат, нажмите кнопку обработчики, такие как:


    document.querySelector('#start').onclick = event => {
    start(data)
    }

    Можно было бы упростить так:

    document.querySelector('#start').onclick = start.bind(null, data)

  • Если вы полностью понимаете, какие способы автоматической вставки точки с запятой может быть нарушена некоторыми заявлениями, добавить точку с запятой, чтобы завершить линию.

  • Аякс statechange обработчик (т. е. зарегистрированы по onreadystatechange) не проверяем readyState и status свойства запроса, и таким образом innerText собственность message скорее всего будут обновлены до желаемого (например, при просьбе открыть, передача, загрузка и т. д.)

Рерайт

Ниже того, что можно сделать с советом выше.



'use strict'

const load = () => {
const data = {};

init(data);

setInterval(() => {
update(data);
render(data);
}, 100);
const mapping = {
"start": start.bind(null, data),
"reset": reset.bind(null, data),
"license": showLicense
};
const clickHandler = event => event.target.id in mapping && mapping[event.target.id]();
document.body.addEventListener('click', clickHandler);
}

const init = data => {
data.canvas = document.getElementById('countdown');
data.ctx = data.canvas.getContext('2d');

data.endTime = Date.now();
data.start = false;
data.reset = false;

data.canvas.width = data.canvas.height = 500;

const inputs = ['hours', 'minutes', 'seconds'];
inputs.forEach(inputName => data[inputName + 'Input'] = document.getElementById(inputName));
data.startButton = document.getElementById('start');
}

const update = data => {
if (data.start || data.reset) {
data.startAngle = timeToAngle(data.endTime);
data.reset = false;
}
if (data.start) {
let difference = Math.abs(Math.floor((data.endTime - Date.now()) / 1000));
let seconds = pad(difference % 60, '00');
difference = Math.floor(difference / 60);
let minutes = pad(difference % 60, '00');
difference = Math.floor(difference / 60);
let hours = difference;

if (data.endTime < Date.now()) {
if (hours != 0) {
hours = -hours;
} else if (minutes != 0) {
minutes = -minutes;
} else {
seconds = -seconds;
}
}

data.hoursInput.value = hours;
data.minutesInput.value = minutes;
data.secondsInput.value = seconds;
}
}

const render = data => {
const {
canvas,
ctx,
startAngle,
start
} = data;

ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, canvas.width, canvas.height);

let angle = Math.abs(startAngle);

ctx.save();

if (startAngle > 0) {
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(-Math.PI / 2);
ctx.scale(1, -1);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
} else {
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(-Math.PI / 2);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
}

while (angle > 2 * Math.PI) {
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI);
ctx.fill();

angle -= 2 * Math.PI;
}

ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle);
ctx.lineTo(canvas.width / 2, canvas.height / 2);
ctx.fill();

ctx.restore();
}

const start = data => {
if (data.start) {
data.startButton.innerText = 'Start';
} else {
let hours = data.hoursInput.value;
let minutes = data.minutesInput.value;
let seconds = data.secondsInput.value;
if (hours.trim() == '') hours = 0;
if (minutes.trim() == '') minutes = 0;
if (seconds.trim() == '') seconds = 0;

let sign;
if (hours != 0) {
sign = hours < 0 ? -1 : 1;
} else if (minutes != 0) {
sign = minutes < 0 ? -1 : 1;
} else {
sign = seconds < 0 ? -1 : 1;
}

minutes = sign * Math.abs(minutes);
seconds = sign * Math.abs(seconds);

data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds;

data.startButton.innerText = 'Pause';
}
data.start ^= true;
}

const reset = data => {
data.endTime = Date.now();
data.start = false;
data.hoursInput.value = '';
data.minutesInput.value = '';
data.secondsInput.value = '';
data.startButton.innerText = 'Start';
data.reset = true;
}

const showLicense = () => {
const mask = document.createElement('div');
mask.id = 'mask';
mask.onclick = () => {
document.body.removeChild(mask);
document.body.removeChild(message);
}
document.body.appendChild(mask);

const message = document.createElement('div');
message.id = 'messageContainer';
message.innerText = 'License unavailable, please report as a bug.';
message.onclick = () => {
document.body.removeChild(mask);
document.body.removeChild(message);
}

const ajax = new XMLHttpRequest();
ajax.open('GET', '/');
ajax.onreadystatechange = () => {
//check state, this doesn't make sense here in this snippet
if (ajax.readyState === 4 && ajax.status === 200) {
//message.innerText = ajax.responseText
}
};
ajax.send();
document.body.append(message);
}

const timeToAngle = endTime => {
const difference = endTime - Date.now();
return difference / 3600000 * 2 * Math.PI;
}

const pad = (value, format) => (format + value).slice(-format.length);

load();


* {
box-sizing: border-box;
}

body {
background: #eee;
margin: 0;
}

main {
background: #fff;
max-width: 700px;
margin: auto;
padding: 10px;
display: flex;
flex-flow: column;
align-items: center;
}

h1 {
text-align: center;
}

menu {
display: flex;
justify-content: space-between;
width: 500px;
padding: 0;
}

#hours,
#minutes,
#seconds {
width: 30px;
text-align: center;
}

footer {
max-width: 700px;
margin: auto;
background: #ddd;
padding: 10px;
display: flex;
justify-content: space-between;
}

footer a {
display: inline-block;
background: #ccc;
padding: 10px;
border-radius: 10px;
color: black;
text-decoration: none;
cursor: pointer;
}

footer a:hover {
background: #888;
color: #fff;
}

#mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1;
}

#messageContainer {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
z-index: 2;
background: #fff;
padding: 10px;
border-radius: 10px;
overflow: auto;
max-width: 600px;
max-height: 500px;
}


<main>
<h1 contenteditable>Countdown</h1>
<canvas id="countdown"></canvas>
<menu>
<button id="reset">Reset</button>
<div class="group">
<input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
</div>
<button id="start">Start</button>
</menu>
</main>
<footer>
<a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
<a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
<a id="license">MIT license</a>
</footer>



1
ответ дан 7 мая 2018 в 04:05 Источник Поделиться