визуальная вставка в реальном времени имеет пробелы и вывод задерживается - PullRequest
0 голосов
/ 06 апреля 2020

Хорошо, я относительно новичок в JS, но у меня большой опыт работы с python и java.

У меня есть 2 вопроса с моим кодом, с которыми мне нужна помощь. Во-первых, вот объяснение и предыстория моего кода.

В идеале я хочу простейшую структурированную программу визуальной сортировки, которую я могу использовать в качестве основы для продвижения моего процесса кодирования к ссылке. Я начал с максимизации контейнера div, который используется для заполнения x количеством элементов divs .bars, ширина и размещение элементов div автоматически обрабатываются flexbox по мере их вставки. Высота каждого добавленного div генерируется случайным образом и сохраняется в атрибутах каждого отдельного элемента. Я сделал все это легко. Затем я сделал функцию замены элементов, которая меняет положение элементов в w DOM, которая отлично работает. Теперь о моих вопросах. Я хотел бы видеть, как элементы сортируются в реальном времени, так как циклы for повторяются, но вместо этого они не обновляются до конца циклов. А также алгоритм My Insertion, в котором я не могу найти никаких ошибок, не работает должным образом, но я не думаю, что мой подход к тому, как он работает, неправильный. Любая помощь будет принята с благодарностью. Это должно быть очень легко понять для кого-то еще.

const sortDisplay = document.getElementById('sortDisplay');
let resetbtn = document.querySelector('.reset');
resetbtn.addEventListener('click', reset);

let count = 0;
let amount = 100;

// create div that has custom attribute value, unique style tag, default bar style and append.
function generateBar() {
  // generate div
  let bar = document.createElement('div');
  // keep track of the total amount of bars
  count++;
  // assign random number 0-100 and setAttribute to the div
  let temp = Math.floor(Math.random() * 101);
  // create custom attribute that holds its value
  bar.setAttribute('value', temp);
  // create unique style tag with height as a percentage based on Attribute
  let barHeight = document.createElement('style');
  barHeight.innerHTML = `.barHeight${count} {height: ${temp}%;}`;
  // add that unique style to the DOM
  sortDisplay.appendChild(barHeight);
  // now add that unique style to the div
  bar.classList.add(`barHeight${count}`);
  // use standard style from css as well
  bar.classList.add('sortBar');
  // now add that div to the DOM
  sortDisplay.appendChild(bar);
}

// clear container div and regenerate
function reset() {
  // clear all data within the container
  sortDisplay.innerHTML = '';
  // reset the count
  count = 0;
  // generate k bars
  for (let i = 0; i < amount; i++) {
    generateBar();
  }
}

// when page is loaded reset
reset(amount);

// swap elements within the DOM
function swapElements(obj1, obj2) {
  // create marker element and insert it above where obj1 is
  var temp = document.createElement("div");
  obj1.parentNode.insertBefore(temp, obj1);
  // move obj1 to right before obj2
  obj2.parentNode.insertBefore(obj1, obj2);
  // move obj2 to right before where obj1 used to be
  temp.parentNode.insertBefore(obj2, temp);
  // remove temporary marker node
  temp.parentNode.removeChild(temp);
}

// sort the divs within the DOM
function sort() {
  for (let i = 1; i < amount; i++) {
    let j = i;
    for (j; j > 0; j--) {
      if (document.querySelectorAll('.sortBar')[j].getAttribute('value') < document.querySelectorAll('.sortBar')[j-1].getAttribute('value')) {
        swapElements(document.querySelectorAll('.sortBar')[j], document.querySelectorAll('.sortBar')[j-1]);
      }
      else {
        break;
      }
    }
  }
}

// Button to run the sort function
button = document.querySelector('.button');
button.addEventListener('click', sort);
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  height: 100vh;
  width: 100%;
}

.sortDisplay {
  background-color: #305c50;
  background-image: linear-gradient(28deg, #305c50 0%, #6ab19e 70%, #82d8a6 100%);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  height: 100%;
  width: 100%;
  overflow: hidden;
}

.btn-container {
  position: absolute;
  right: 0;
  bottom: 0;
  margin: 25px;
}

.btn-container button {
  padding: 25px;
}

.sortBar {
  flex: 1;
  background-color: #0007;
}
<div class="btn-container">
  <button class="reset">reset</button>
  <button class="button">button</button>
</div>

<div id="sortDisplay"class="sortDisplay"></div>

1 Ответ

0 голосов
/ 06 апреля 2020

Ошибка очень незначительная: вы сравниваете строки, а не числа в вашем роде. Добавьте преобразование чисел:

if (+document.querySelectorAll('.sortBar')[j].getAttribute('value') < +document.querySelectorAll('.sortBar')[j-1].getAttribute('value')) {

В виде строк, например, "3" > "29".

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

Чтобы исправить это, добавьте задержку в циклы, это очень просто, все, что вам нужно является канонической функцией задержки (const delay = ms => new Promise(res => setTimeout(res, ms));), async перед вашим sort (async function sort) и соответствующей задержкой между свопами (await delay(DELAY_BETWEEN_SWAPS);, 25 мс в настоящее время. Точное время не гарантируется, оно может потребоваться, например, 22 мс один раз и 27 мс в следующий раз из-за множества факторов, но это не так уж важно).

Однако это вызывает проблемы с отменой: теперь возможно выполнить сброс, а сортировка все еще продолжается (дилемма аснихронности). Поэтому необходимо проверить, была ли текущая сортировка отменена или нет. Поэтому для каждого процесса сортировки требуется токен отмены, который можно использовать для остановки старой сортировки при нажатии кнопки сброса. И последнее, но не менее, начиная новую сортировку (просто нажав «кнопку»), автоматически отменяется и последняя сортировка.

Обратите внимание, что я показываю некоторые концепции, но не обязательно код, который получит награды за красоту. Я также не изменяю ничего, что «работает, но я бы так не делал» - например, я бы предпочел холст вместо анимации с тоннами DOM-обновлений.

Рабочая версия:

const sortDisplay = document.getElementById('sortDisplay');
let resetbtn = document.querySelector('.reset');
resetbtn.addEventListener('click', reset);

const DELAY_BETWEEN_SWAPS = 25;

const delay = ms => new Promise(res => setTimeout(res, ms));

let cancelLast = () => {};

let count = 0;
let amount = 100;

// create div that has custom attribute value, unique style tag, default bar style and append.
function generateBar() {
  // generate div
  let bar = document.createElement('div');
  // keep track of the total amount of bars
  count++;
  // assign random number 0-100 and setAttribute to the div
  let temp = Math.floor(Math.random() * 101);
  // create custom attribute that holds its value
  bar.setAttribute('value', temp);
  // create unique style tag with height as a percentage based on Attribute
  let barHeight = document.createElement('style');
  barHeight.innerHTML = `.barHeight${count} {height: ${temp}%;}`;
  // add that unique style to the DOM
  sortDisplay.appendChild(barHeight);
  // now add that unique style to the div
  bar.classList.add(`barHeight${count}`);
  // use standard style from css as well
  bar.classList.add('sortBar');
  // now add that div to the DOM
  sortDisplay.appendChild(bar);
}

// clear container div and regenerate
function reset() {
  cancelLast();
  // clear all data within the container
  sortDisplay.innerHTML = '';
  // reset the count
  count = 0;
  // generate k bars
  for (let i = 0; i < amount; i++) {
    generateBar();
  }
}

// when page is loaded reset
reset(amount);

// swap elements within the DOM
function swapElements(obj1, obj2) {
  // create marker element and insert it above where obj1 is
  var temp = document.createElement("div");
  obj1.parentNode.insertBefore(temp, obj1);
  // move obj1 to right before obj2
  obj2.parentNode.insertBefore(obj1, obj2);
  // move obj2 to right before where obj1 used to be
  temp.parentNode.insertBefore(obj2, temp);
  // remove temporary marker node
  temp.parentNode.removeChild(temp);
}

// sort the divs within the DOM
async function sort(cancellationChecker) {
  for (let i = 1; i < amount; i++) {
    let j = i;
    for (j; j > 0; j--) {
      if (cancellationChecker()) return;
      if (+document.querySelectorAll('.sortBar')[j].getAttribute('value') < +document.querySelectorAll('.sortBar')[j-1].getAttribute('value')) {
        swapElements(document.querySelectorAll('.sortBar')[j], document.querySelectorAll('.sortBar')[j-1]);
        await delay(DELAY_BETWEEN_SWAPS);
      }
      else {
        break;
      }
    }
  }
}

function btnSort() {
  let cancelled = false;
  cancelLast();
  cancelLast = () => cancelled = true;
  sort(() => cancelled);
}

// Button to run the sort function
button = document.querySelector('.button');
button.addEventListener('click', btnSort);
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  height: 100vh;
  width: 100%;
}

.sortDisplay {
  background-color: #305c50;
  background-image: linear-gradient(28deg, #305c50 0%, #6ab19e 70%, #82d8a6 100%);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  height: 100%;
  width: 100%;
  overflow: hidden;
}

.btn-container {
  position: absolute;
  right: 0;
  bottom: 0;
  margin: 25px;
}

.btn-container button {
  padding: 25px;
}

.sortBar {
  flex: 1;
  background-color: #0007;
}
<div class="btn-container">
  <button class="reset">reset</button>
  <button class="button">button</button>
</div>

<div id="sortDisplay"class="sortDisplay"></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...