Задать вопрос
  • Как перевести дату в строке в формат UNIX?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const months = Object.fromEntries(Array.from(
      { length: 12 },
      (_, i) => [ new Date(0, i).toLocaleString('ru-RU', { month: 'long' }), i ]
    ));
    
    function parseDate(str) {
      const [ , month, day, year, hour, minute ] = str.match(/(\S+) (\d+), (\d+) (\d+):(\d+)/);
      return +new Date(year, months[month.toLowerCase()], day, hour, minute);
    }
    Ответ написан
    1 комментарий
  • Как отрендерить календарь, чтобы числа дней выводились в соответствии с днями недели?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Отдельные циклы для чисел за текущий и предыдущий месяцы (кстати, а где у вас следующий?) не нужны. Чтобы получить число, надо не на счётчик цикла смотреть, а на дату - начальным значением будет первое число месяца минус количество дней, прошедших с последнего понедельника. Цикл крутить надо не до конца месяца, а немного дальше - чтобы общее количество чисел было кратно семи (т.е., чтобы в последней неделе не было отсутствующих дней) и всегда одно и то же (чтобы размер календаря не зависел от отображаемого месяца). Вот так.
    Ответ написан
    Комментировать
  • Как в react выделить все чекбоксы?

    0xD34F
    @0xD34F Куратор тега React
    const Checkbox = forwardRef(({ label, ...props }, ref) =>
      <label>
        <input type="checkbox" ref={ref} {...props} />
        {label}
      </label>
    );
    
    function CheckboxGroup({
      items,
      label = item => item,
      selected,
      setSelected,
    }) {
      const onChange = ({ target: { checked, dataset: { index } } }) =>
        setSelected(selected => checked
          ? [ ...selected, items[index] ]
          : selected.filter(n => n !== items[index])
        );
    
      const allSelectedRef = useRef();
      const onAllSelectedChange = ({ target: { checked } }) =>
        setSelected(checked ? [...items] : []);
    
      useEffect(() => {
        const isAllSelected = items.length === selected.length;
        allSelectedRef.current.checked = isAllSelected;
        allSelectedRef.current.indeterminate = !isAllSelected && !!selected.length;
      }, [ selected ]);
    
      return (
        <div className="checkbox-group">
          <Checkbox
            label="SELECT ALL"
            defaultChecked={false}
            onChange={onAllSelectedChange}
            ref={allSelectedRef}
          />
          {items.map((n, i) => (
            <Checkbox
              label={label(n)}
              data-index={i}
              checked={selected.includes(n)}
              onChange={onChange}
            />
          ))}
        </div>
      );
    }

    https://jsfiddle.net/kj9wet6L/
    Ответ написан
    Комментировать
  • Как сделать такой фильтр опций на js или jq?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где находятся чекбоксы и фильтруемые элементы, какой класс обеспечивает сокрытие элементов:

    const checkboxContainer = document.querySelector('.options');
    const itemsContainer = document.querySelector('.box');
    const hiddenClass = 'hidden';

    Собираем селектор на основе состояний чекбоксов (выставлен - класс должен присутствовать, не выставлен - помещаем класс внутрь :not):

    function getCheckedSelector(container) {
      const [ not, has ] = Array.prototype.reduce.call(
        container.querySelectorAll('input'),
        (acc, n) => (acc[+n.checked].push(`.${n.value}`), acc),
        [ [], [] ]
      );
    
      return has.join('') + (not.length ? `:not(${not.join(',')})` : '');
    }

    Затем проверяем фильтруемые элементы на соответствие селектору:

    checkboxContainer.addEventListener('change', function() {
      const selector = getCheckedSelector(this);
    
      for (const n of itemsContainer.children) {
        n.classList.toggle(hiddenClass, !n.matches(selector));
      }
    });

    Или сначала прячем всё, а потом показываем что надо:

    const toggleHidden = (selector, state) => itemsContainer
      .querySelectorAll(selector)
      .forEach(n => n.classList.toggle(hiddenClass, state));
    
    checkboxContainer.addEventListener('change', e => {
      toggleHidden(':scope > *', true);
      toggleHidden(getCheckedSelector(e.currentTarget), false);
    });

    ИЛИ

    При обработке элемента перебираем чекбоксы и проверяем, что их состояния соответствуют наличию классов у данного элемента:

    const checkboxes = [...checkboxContainer.querySelectorAll('input')];
    const onChange = function() {
      this.forEach(({ classList: cl }) => {
        cl.toggle(hiddenClass, checkboxes.some(n => n.checked !== cl.contains(n.value)));
      });
    }.bind([...itemsContainer.children]);
    
    checkboxes.forEach(n => n.addEventListener('change', onChange));
    Ответ написан
  • Как добавить/ удалить класс каждые 3 секунды в Vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const blocks = ref(Array.from({ length: 5 }, (_, i) => (-~i) ** 2));
    const active = ref(0);
    
    function next() {
      active.value = (active.value + 1 + blocks.value.length) % blocks.value.length;
    }
    
    let intervalId = null;
    onMounted(() => intervalId = setInterval(next, 500));
    onUnmounted(() => clearInterval(intervalId));

    <div
      v-for="(n, i) in blocks"
      v-text="n"
      :class="[ 'box-item', { active: i === active } ]"
    ></div>

    Конечно, зашивать в стили цвета блоков и их количество - все эти :nth-child - не круто. Лучше сделать компонент, принимающий массив цветов и создающий блоки на его основе. Соответственно, вместо класса будет назначаться цвет фона напрямую, как-то так:

    <div
      v-for="(n, i) in colors"
      :style="{ backgroundColor: i === active ? n : '' }"
      ...
    Ответ написан
    2 комментария
  • Как мне сделать так, чтобы slice был для каждого компонента свой?

    0xD34F
    @0xD34F Куратор тега React
    кликая на один список открывается и второй

    Ну ещё бы не открывался. А как конкретно накосячили - забыли передать dropdownId или тупо скопипастили уже существующий?

    Если каждому экземпляру Dropdown передавать уникальный dropdownId, то открываться будет один. Если открываться должны независимо, то вместо хранения одного id можно сделать объект, где id будут ключами.
    Ответ написан
  • Как осуществлять фильтрацию по нескольким свойствам?

    0xD34F
    @0xD34F Куратор тега React
    Вместо общего массива выбранных значений сделать отдельные для каждого из свойств.

    Чтобы не дублировались чекбоксы, создавать их на основе уникализированных массивов значений свойства вместо массива данных.

    Чтобы поменьше копипастить, оформить чекбоксы в отдельный компонент - принимает массив доступных значений, массив выбранных значений, функцию установки выбранных значений.

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

    https://jsfiddle.net/bqyxa0kL/
    Ответ написан
    Комментировать
  • Как убрать фокус с компонента DateTimePicker при нажатии на ok?

    0xD34F
    @0xD34F Куратор тега Vue.js
    function onVisibleChange(state) {
      if (!state) {
        document.activeElement.blur();
      }
    }

    <el-date-picker
      @visible-change="onVisibleChange"
      ...
    Ответ написан
    Комментировать
  • Почему не обновляется пропс?

    0xD34F
    @0xD34F Куратор тега Vue.js
    почему при изменении даты передаваемой в пропс не обновляется значение в самом компоненте таймера?

    Встречный вопрос - почему вы решили, что внутреннее состояние компонента обновляться должно? Покажите, где вы обновляете targetDate при изменении props.date. Нет, можете себя не утруждать - ничего такого у вас нет.

    Не надо никакого targetDate, рассчитываем дни-часы-минуты-секунды сразу на основе props.date - так при изменении props.date не придётся предпринимать никаких дополнительных телодвижений, всё посчитается как надо при следующем вызове updateCountdown. Вот как-то так.
    Ответ написан
    Комментировать
  • Как разбить многостроковый текст на массив с помощью регулярного выражения?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Понимаю что можно сделать проще с помощью split, но хочу научиться именно с помощью регулярного выражения

    Одно другому не мешает:

    str.split(/\n(?=#EXTINF)/)
    Ответ написан
    Комментировать
  • Как кликать на вложенные элементы так, чтобы не кликался родительский элемент?

    0xD34F
    @0xD34F Куратор тега JavaScript
    .data-accordion--summary-container.active > .dropdown {
      display: block;
    }

    const itemSelector = '.data-accordion--summary-container';
    const activeClass = 'active';
    const toggle = el =>
      el.parentNode.querySelectorAll(`:scope > ${itemSelector}`).forEach(n => {
        n.classList[n === el ? 'toggle' : 'remove'](activeClass);
      });
    
    
    // применяем делегирование
    document.body.addEventListener('click', ({ target: t }) => {
      if (t.matches(itemSelector)) {
        toggle(t);
      }
    });
    
    // или, назначаем обработчик клика каждому элементу индивидуально
    document.querySelectorAll(itemSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, e => e.currentTarget === e.target && toggle(e.target));
    Ответ написан
    Комментировать
  • Как из query string получить объект следующего вида?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Просто исправить существующий код:

    - acc[key] = [value];
    + (acc[key] ??= []).push(value);

    Но можно его ещё и сократить:

    const convertQueryStringToObject = str => Array
      .from(new URLSearchParams(str))
      .reduce((acc, n) => ((acc[n[0]] ??= []).push(n[1]), acc), {});

    Или неоправданно усложнить и изуродовать:

    const convertQueryStringToObject = str => Array
      .from(str.matchAll(/([^&]+)=([^&]+)/g))
      .reduce((acc, [ , k, v ]) => (
        Object.hasOwn(acc, k) || (acc[k] = []),
        acc[k][acc[k].length] = v,
        acc
      ), {});
    Ответ написан
    1 комментарий
  • Как убрать scroll у body при открытии модальных окон через vue watch?

    0xD34F
    @0xD34F Куратор тега Vue.js
    .no-overflow {
      overflow: hidden;
    }

    mounted() {
      this.$watch(
        () => this.isModalAddVisible || this.activeId,
        val => document.body.classList.toggle('no-overflow', val),
        { immediate: true }
      );
    },

    Одно непонятно - зачем отслеживать несколько разных свойств, если наличием скролла может управлять само модальное окно? Открылось - убирает скролл, закрылось - возвращает. Разные окна для разных задача? - сделайте общий компонент, а разницу для конкретных экземпляров определяйте через слоты.
    Ответ написан
    Комментировать
  • Как переместить элемент в блоке вверх по клику?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Данные слайдов сложить в массив. Сделать вычисляемое свойство - данные всех слайдов кроме верхнего. Создать верхний слайд, создать остальные слайды на основе вычисляемого свойства. Если нужна анимация перемещения, завернуть слайды в transition-group. Вот так всё просто.
    Ответ написан
    1 комментарий
  • Как динамически добавлять текстовые поля в форму редактирования строки таблицы с использованием Quasar?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сложить имена основных полей в массив.

    Сделать вычисляемое свойство, представляющее имена дополнительных полей - надо получить список ключей editedItem и выкинуть из него имена основных полей.

    В диалоговом окне сделать v-for по массиву дополнительных полей.

    Всё.
    Ответ написан
    Комментировать
  • Как реализовать эффект печатающегося текста?

    0xD34F
    @0xD34F Куратор тега React
    Состояние компонента должно содержать три значения - индекс печатаемой строки, количество отображаемых символов, направление печати (печатаем или стираем, т.е., в какую сторону надо изменять количество отображаемых символов, увеличивать или уменьшать). Дальше понятно что - setInterval или рекурсивный setTimeout, изменяем количество отображаемых символов, если дошли до конца строки - меняем направление, дошли до начала - меняем направление и индекс строки. Вот как-то так:

    const defaults = {
      index: 0,
      length: 0,
      step: 1,
    };
    
    function Typewriter({ strings, delay }) {
      const [ state, setState ] = useState(null);
    
      useEffect(() => {
        setState(() => ({...defaults}));
      }, [ strings ]);
    
      useEffect(() => {
        const timeoutId = setTimeout(setState, delay, ({...state}) => {
          state.length += state.step;
          if (state.length === strings[state.index].length) {
            state.step = -1;
          } else if (state.length === 0) {
            state.step = 1;
            state.index = (state.index + 1) % strings.length;
          }
          return state;
        });
    
        return () => clearTimeout(timeoutId);
      });
    
      return <div>{strings?.[state?.index]?.slice(0, state?.length)}</div>;
    }
    Ответ написан
    8 комментариев
  • Как высчитать уровень исходя из массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    работает, но кажется, что достаточно криво

    Да, криво - всегда перебирается весь массив.

    Можно идти от конца к началу до тех пор, пока не встретится подходящий элемент:

    let lvl = 0;
    
    for (let i = LVLS.length; i--;) {
      if (LVLS[i].exp <= EXP) {
        lvl = LVLS[i].lv;
        break;
      }
    }

    переделать это во что-то более красивое

    const lvl = LVLS.findLast(n => n.exp <= EXP)?.lv ?? 0;

    А вообще, учитывая, что уровни представлены натуральными числами без пропусков, отдельные свойства под их значения не нужны, можно искать индекс:

    const LVLS = [ 10, 25, 45, 70, 100 ];
    
    const lvl = 1 + LVLS.findLastIndex(n => n <= EXP);
    Ответ написан
    Комментировать
  • Как получить свойство из props drilling по открытию модального окна?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Не надо никаких v-model, кого показывать в модальном окне - отправляйте наверх эту информацию вместе с событием. Свойство, управляющее видимостью модального окна - пусть оно вместо логического значения хранит id или объект или что там у вас должно показываться в окне, если не null, значит открываем окно. Вот так всё просто.

    UPD. Вот вариант с v-model, конечно только на уровне таблицы, в строках всё по-прежнему.

    UPD. А вообще, можно полностью отказаться от прокидывания событий наверх. Таблицу исполняем в более общем виде - пусть принимает массив с описанием столбцов, а содержимое ячеек задаётся через слоты, имена которых определяются на основе имён столбцов (по умолчанию выводят данных как есть). В этом случае кнопку можно определить там же, где создаётся экземпляр таблицы. Как это может выглядеть - ваш вариант с отдельным компонентом строки (и, соответственно, прокидыванием в него слотов из компонента таблицы), или, без ненужного усложнения.
    Ответ написан
    1 комментарий
  • Как отобразить данные по тегам из json на странице?

    0xD34F
    @0xD34F Куратор тега JavaScript
    <button data-country="">Показать всё</button>
    <button data-country="France">Франция</button>
    <button data-country="Germany">Германия</button>
    <button data-country="England">Англия</button>

    const catalogEl = document.querySelector('#catalog-box');
    let catalogArr = [];
    
    const buttons = document.querySelectorAll('button[data-country]');
    buttons.forEach(n => n.addEventListener('click', onClick));
    
    function onClick({ target: t }) {
      buttons.forEach(n => n.classList.toggle('active', n === t));
      renderCatalog(t.dataset.country);
    }
    
    function renderCatalog(country) {
      const toRender = country
        ? catalogArr.filter(n => n.tag === country)
        : catalogArr;
    
      catalogEl.innerHTML = toRender
        .map(n => `
          <div class="catalog__card" id="${n.id}">
            <img src="${n.img}" alt="${n.alt}" class="catalog__card_img">
            <p class="catalog__card_author">${n.author}</p>
            <p class="catalog__card_name">${n.name}</p>
            <p class="catalog__card_note">${n.note}</p>
            <p class="catalog__card_price">${n.price}</p>
            <button class="catalog__card_btn">${n.btn}</button>
          </div>`)
        .join('');
    }
    
    fetch('catalogBox.json')
      .then(r => r.json())
      .then(r => {
        catalogArr = r;
        buttons[0].click();
      });
    Ответ написан
    Комментировать