Выполнить функцию после повторного рендеринга макета в Svelte - PullRequest
0 голосов
/ 20 октября 2019

Я хотел бы создать всплывающее меню, когда я нажимаю на строку таблицы в svelte. Я использовал метод document.querySelectorAll, чтобы добавить событие onclick к каждой строке таблицы внутри onMount. В функции onMount я также повторно отображаю отображаемую таблицу. Как я могу применить значение onclick к повторно отображаемым элементам?

onMount(() => {
  console.log(document.querySelectorAll(".results .table table tbody tr"));
  /* -> returns array with only 1 element -> not correct */

  /* ... re-render logic here */
}

, но когда я добавляю таймаут:

onMount(() => {
  setTimeout(() => {
      console.log(document.querySelectorAll(".results .table table tbody tr"));
  }, 5000);
  /* -> returns array with all elements */

  /* ... re-render logic here again */
}

Можно найти REPL с полным исходным кодом здесь

1 Ответ

1 голос
/ 24 октября 2019

Я писал некоторые мысли, но это было слишком долго для комментария.

Вы выполняете приличный объем дополнительной работы в этом REPL, который Svelte может сделать для вас. Я согласен с @voscausa, что вы должны делегировать события на table. Вы почти никогда не должны использовать document.querySelector в Svelte. Вы дважды просматриваете все свои ряды. Все ваши вложения прослушивателя событий должны быть атрибутами в разметке, не прикрепленными в JS или присоединенными в функции инициализатора (таким образом, делегирование события в таблицу). Вы постоянно отслеживаете положение мыши, но используете его только в onclick, который является MouseEvent и имеет доступ к данным X и Y.

Переключите прослушиватель щелчка на контейнер:

<div class="results" on:click={handleClick}> ... </div>

<script>
  function handleClick(e) {
    const tr = e.target.closest('tr');
    const td = e.target.closest('td');
    if (td) {
      /* code */
    } else {
      /* code */
    }
  }
  </script>

Если вам нужно, чтобы он был на всем документе, вы можете использовать <svelte:window> вместо .results.

Чтобы обновить CSS элемента .option, выполните что-то вроде следующего:

<div class="options" style=`left:${optionsStyle.left}px;top:${optionsStyle.top}px`> ... </div>
<script>
  let optionsStyle = {left: 0, top: 0};

  function handleClick(e) {
    /* code */

    let left = 0, right = 0;
    /* calculate left and right here */
    optionsStyle  = {left: e.clientX, top: e.clientY};

    /* code */
  }
</script>

Для переключения классов см. Директиву class . Вы можете иметь несколько директив класса на один элемент. (Я, конечно, не выполнил всю логику здесь.)

<div class="options" class:expand={optionsExpand}> ... </div>
<script>
  let optionsExpand = false;

  function handleClick(e) {
    const tr = e.target.closest('tr');
    const td = e.target.closest('td');
    if (td) {
      /* code */
      optionsExpand = true;
    } else {
      /* code */
      optionsExpand = false;
    }
  }
</script>

Лично я бы превратил всплывающее окно Options в его собственный компонент и передал бы optionsExpand boolean как пропеллер.

Выполнение вещей, подобных описанным здесь, заставит вас задуматься над Svelte, это упростит ваш код, вам не понадобятся тайм-ауты и вам не понадобится функция afterUpdates.

...