Почему не работает, если статусы повторяются в JavaScript? - PullRequest
0 голосов
/ 06 августа 2020

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

Мне удалось заставить работать первый, и я подумал, что могу просто повторить код с другими назначенными переменными, однако это не сработало. Странно то, что если я удалю код для первого поля, второе поле начнет работать.

Нужно ли мне добавлять дополнительный код в JS для разделения состояний if?

CSS '

.grid-container {
  display: grid;
  grid-gap: 50px;
  grid-template-columns: auto auto auto;
  background-color: grey;
  padding: 10px;
}

.grid-item {
  background-color: green;
  border: 1px solid rgba(0, 0, 0, 0.8);
  padding: 50px;
  font-size: 30px;
  text-align: center;
}

HTML

<div class="grid-container">
  <div class="grid-item" id = "blink1">A</div>
  <div class="grid-item" id = "blink2">B</div>
 
</div>


<div class = "values">  
<div id = "$box1value"> 1 </div>
<div id = "$box2value"> 1 </div>
</div>

JS

var $box1 = document.getElementById("$box1value").innerHTML;

if ($box1 > 0) {
    document.getElementById("blink1").style.backgroundColor = '#ff0000';
    // blink "on" state
    function show() {
        if (document.getElementById)
            document.getElementById("blink1").style.visibility = "visible";
    }
    // blink "off" state
    function hide() {
        if (document.getElementById)
            document.getElementById("blink1").style.visibility = "hidden";
    }

    for (var i = 900; i < 99999999999; i = i + 900) {
        setTimeout("hide()", i);
        setTimeout("show()", i + 450);
    }

} else {
    document.getElementById("blink1").style.backgroundColor = '#098700';
}




/////////////////////next box/////////////////////////////

var $box2 = document.getElementById("$box2value").innerHTML;

if ($box2 > 0) {
    document.getElementById("blink2").style.backgroundColor = '#ff0000';// blink "on" state
    function show() {
        if (document.getElementById)
            document.getElementById("blink2").style.visibility = "visible";
    }
    // blink "off" state
    function hide() {
        if (document.getElementById)
            document.getElementById("blink2").style.visibility = "hidden";
    }

    for (var i = 900; i < 99999999999999999; i = i + 900) {
        setTimeout("hide()", i);
        setTimeout("show()", i + 450);
    }

} else {
    document.getElementById("blink2").style.backgroundColor = '#098700';
}

Ответы [ 2 ]

2 голосов
/ 06 августа 2020

2 различных решения (все JS по сравнению с большинством CSS)

  1. Сохранение основных функций в JS
  2. Использование CSS для основных функций

Я вижу, чего вы здесь пытаетесь достичь, и вижу несколько sh способов сделать это. Оба решения ниже позволяют вашему коду динамически l oop проходить через любое количество элементов коробки - нет необходимости писать отдельный блок для каждого элемента.

Первый пример ниже смоделирован более похожим на ваш, на основе в вашем коде, но переписан, чтобы работать более динамично. Второе решение значительно упрощает ситуацию, перемещая все сценарии инициализации в CSS, оставляя JS ответственным только за логическое переключение, если вам нужно сделать какие-либо переключения состояния в реальном времени.

# 1. Сохранение основных функций в JS

Это решение изменяет исходный код, чтобы динамически считывать значения для любого количества значений, а затем перебирать их. Чтобы выполнить повторное мигание в JS, я бы предложил использовать setInterval. Вам также необходимо переместить это за пределы остальной части кода при использовании al oop, иначе вы получите конфликт между итератором l oop и временем setInterval и setTimeout. Подробнее об этом здесь . Вы можете увидеть рабочий пример ниже:

function blink(el) {
    if (el.style) {
        setInterval(function() {
            el.style.visibility = "visible";
            setTimeout(function() {
                el.style.visibility = "hidden";
            }, 450);
        }, 900);
    }
}

const $boxes = document.querySelectorAll('[id^="blink"]');
for (const $box of $boxes) {
    var boxId = $box.id.match(/\d+/)[0]; // store the ID #
    if (document.getElementById('$box' + boxId + 'value')) {
        var boxValue = parseInt(document.getElementById('$box' + boxId + 'value').innerHTML);
        if (boxValue) {
            $box.style.backgroundColor = '#ff0000';
            blink($box);
        } else {
            $box.style.backgroundColor = '#098700';
        }
    }
}
.grid-container {
    display: grid;
    grid-gap: 50px;
    grid-template-columns: auto auto auto;
    background-color: grey;
    padding: 10px;
}
.grid-item {
    background-color: #098700;
    border: 1px solid rgba(0, 0, 0, 0.8);
    padding: 50px;
    font-size: 30px;
    text-align: center;
}
.values {
    display: none;
}
<div class="grid-container">
    <div class="grid-item" id="blink1">A</div>
    <div class="grid-item" id="blink2">B</div>
    <div class="grid-item" id="blink3">C</div>
</div>
<div class="values">  
    <div id="$box1value">1</div>
    <div id="$box2value">0</div>
    <div id="$box3value">1</div>
</div>

CodePen: https://codepen.io/brandonmcconnell/pen/ecc954bad5552962574c080631700932

# 2. Использование CSS для основных функций

Это решение перемещает весь ваш код JS (цвет и анимацию) в CSS, перемещая двоичный логический переключатель 0/1 в атрибуты данных в сетке - элементы сами по себе, а не отдельные элементы, а затем запускают любые логические переключатели в этих контейнерах, используя JS, нацеливая их на другой атрибут, такой как ID, или, как я использовал в моем примере ниже, другой атрибут данных я назвал data-blink-id. Это мое рекомендуемое решение, если вы можете переместить все эти logi c в CSS. Будет намного проще поддерживать и манипулировать им в реальном времени, поскольку все, что требуется для изменения состояния, - это простой логический переключатель.

.grid-container {
    display: grid;
    grid-gap: 50px;
    grid-template-columns: auto auto auto;
    background-color: grey;
    padding: 10px;
}
.grid-item {
    background-color: #098700;
    border: 1px solid rgba(0, 0, 0, 0.8);
    padding: 50px;
    font-size: 30px;
    text-align: center;
}
.grid-item[data-blink-status="1"] {
    background-color: #f00;
    animation: blink 900ms linear infinite forwards;
}
@keyframes blink {
    0%, 50% { opacity: 1; }
    51%, 100% { opacity: 0; }
}
<div class="grid-container">
    <div class="grid-item" data-blink-id="1" data-blink-status="1">A</div>
    <div class="grid-item" data-blink-id="2" data-blink-status="0">B</div>
    <div class="grid-item" data-blink-id="3" data-blink-status="1">C</div>
</div>

CodePen: https://codepen.io/brandonmcconnell/pen/5b4f3090b3590902b11d50af43361758

Для запуска двоичного логического переключателя на элементе (включить / выключить), используйте команду JS ниже. Я прокомментировал это в приведенном выше примере CodePen. Снимите комментирование этой строки JS, чтобы активировать ее, и включите блок с помощью data-blink-id=2

document.querySelector('[data-blink-id="2"]').setAttribute('data-blink-status', 1);
0 голосов
/ 06 августа 2020

Несмотря на то, что ваши функции объявлены внутри операторов if, они по-прежнему являются глобальными.

Итак, вы по существу повторно объявляете функции show и hide, и они перестают работать.

Чтобы сделать эти функции локальными для оператора if, вам нужно будет использовать одно из объявлений области видимости блока ES6, let или const, например:

const show = function(){ ... }
const hide = function(){ ... }

To do при этом вам также следует заменить первый аргумент setTimeout ссылкой на функцию (на самом деле, вы всегда должны это делать):

setTimeout(hide, i)
setTimeout(show, i + 450)

Другие улучшения, которые вы можете сделать:

  • Избегайте l oop, которое устанавливает таймауты. Это уродливо, требует много времени на выполнение и не работает вечно. Вместо этого замените setTimeout s на setInterval s.
  • Удалите часть if (document.getElementById). Вы можете рассчитывать на то, что он будет определен (он был loooong time ...)

Итак, вы получите:

var $box1 = document.getElementById("$box1value").innerHTML;

if ($box1 > 0) {
    document.getElementById("blink1").style.backgroundColor = '#ff0000';// blink "on" state
    const show = function () {
        document.getElementById("blink1").style.visibility = "visible";
    }
    // blink "off" state
    const hide = function () {
        document.getElementById("blink1").style.visibility = "hidden";
    }

    let flag = false //This is needed to keep track if the element is visible

    setInterval(function(){
      if(flag = !flag)
        hide()
      else
        show()
    }, 450);

} else {
    document.getElementById("blink1").style.backgroundColor = '#098700';
}

/////////////////////next box/////////////////////////////

var $box2 = document.getElementById("$box2value").innerHTML;

if ($box2 > 0) {
    document.getElementById("blink2").style.backgroundColor = '#ff0000';// blink "on" state
    const show = function () {
        document.getElementById("blink2").style.visibility = "visible";
    }
    // blink "off" state
    const hide = function () {
        document.getElementById("blink2").style.visibility = "hidden";
    }

    let flag = false //This is needed to keep track if the element is visible

    setInterval(function(){
      if(flag = !flag)
        hide()
      else
        show()
    }, 450);

} else {
    document.getElementById("blink2").style.backgroundColor = '#098700';
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...