Задать вопрос
Ответы пользователя по тегу JavaScript
  • Как удалить копии добавленного блока?

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

    const $inner = $('.inner');
    if (!$inner.find('.butt_back').length) {
      $inner.append(...);
    }


    Или, если вам действительно надо удалять предыдущие:

    $('.inner')
      .find('.butt_back').remove()
      .end()
      .append(...);
    Ответ написан
    Комментировать
  • Почему не работает клонирование canvas?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Что не так ?

    Да всё не так.

    Что за clone? - у DOM-узлов такого метода нет. Есть cloneNode. Или используйте jquery (судя по тому, что контекст вы пытаетесь получить у clone[0], так и предполагалось), там clone есть: $(canvas).clone().

    Копировать содержимое оригинала вы пытаетесь до того, как оно вообще будет загружено. Выполняйте копирование в onload.

    Копируете непонятно откуда:

    canvas = document.getElementById('myCanvas');
    <...>
    drawImage(canvas[0],

    Опять же - либо canvas = $('#myCanvas'), либо drawImage(canvas,.

    UPD. Должно было быть так?
    Ответ написан
    3 комментария
  • Как запустить функцию только один раз?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Удаляйте обработчик после того, как он выполнил нужное действие:

    $(window).scroll(function onScroll() {
      const $this = $(this);
      if ($this.scrollTop() > scrollToElem) {
        $('#popup-item').addClass('popup-open');
        $this.off('scroll', onScroll);
      }
    });
    Ответ написан
    Комментировать
  • Как остановить setInterval из другой функции?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.addEventListener('mouseover', ({ target: t }) => {
      if (t.classList.contains('pic') && !t.dataset.interval) {
        t.dataset.interval = bgRotate(t);
      }
    });
    
    document.addEventListener('mouseout', ({ target: t }) => {
      const { interval } = t.dataset;
      if (interval) {
        clearInterval(interval);
        delete t.dataset.interval;
      }
    });

    или

    document.querySelectorAll('.pic').forEach(n => {
      n.addEventListener('mouseenter', onHover);
      n.addEventListener('mouseleave', onHover);
    });
    
    function onHover({ type, target: t }) {
      const d = t.dataset;
      if (type === 'mouseenter' && !d.interval) {
        d.interval = bgRotate(t);
      } else if (type === 'mouseleave') {
        clearInterval(d.interval);
        delete d.interval;
      }
    }
    Ответ написан
  • Как сделать смену картинок на jquery с помощью радиокнопок?

    0xD34F
    @0xD34F Куратор тега JavaScript
    .images_box a {
      display: none;
    }
    
    .images_box a.active {
      display: inline;
    }

    const containerSelector = '.items-list-item-wrapper';
    const buttonSelector = '.items-list-item-colors input';
    const contentSelector = '.images_box a';
    const activeClass = 'active';
    
    
    // jquery, как вы и хотели
    $(containerSelector).on('change', buttonSelector, function(e) {
      $(contentSelector, e.delegateTarget)
        .removeClass(activeClass)
        .eq($(buttonSelector, e.delegateTarget).index(this))
        .addClass(activeClass);
    }).each((i, n) => $(buttonSelector, n).first().click());
    
    // или, к чёрту jquery
    document.querySelectorAll(containerSelector).forEach(n => {
      n.addEventListener('change', onChange);
      n.querySelector(buttonSelector).click();
    });
    
    function onChange({ target: t }) {
      if (t.matches(buttonSelector)) {
        const buttons = this.querySelectorAll(buttonSelector);
        const index = Array.prototype.indexOf.call(buttons, t);
        this.querySelectorAll(contentSelector).forEach((n, i) => {
          n.classList.toggle(activeClass, i === index);
        });
      }
    }
    Ответ написан
    Комментировать
  • Как скрыть блок при повторном нажатии на javascript?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Как заставить работать по-быстрому:
    function navFunction(id) {
      for (const n of document.querySelectorAll('.dropdown2-content')) {
        n.classList[n.id === id ? 'toggle' : 'remove']('show');
      }
    }

    Но вообще, тут многое можно изменить:

    Разметка - вырезать инлайновые обработчики клика и атрибуты id.

    Стили - будем плясать от корневых элементов (так удобнее; кроме того, если в будущем захотите стилизовать в "открытом" дропдауне что-то кроме контента, то не будет необходимости добавлять этим элементам классы, и, соответственно, не придётся переписывать код):

    .dropdown2 .dropdown2-content {
      display: none;
    }
    
    .dropdown2.show .dropdown2-content {
      display: block;
    }

    Код - вместо id будет смотреть на взаимное расположение элементов (переключаем класс у предка нажатой кнопки, у остальных удаляем):

    const containerSelector = '.dropdown2';
    const buttonSelector = `${containerSelector} .dropbtn2`;
    const activeClass = 'show';
    
    
    // делегирование, назначаем обработчик клика один раз для всех кнопок
    document.addEventListener('click', e => {
      const button = e.target.closest(buttonSelector);
      if (button) {
        document.querySelectorAll(containerSelector).forEach(function(n) {
          n.classList[n === this ? 'toggle' : 'remove'](activeClass);
        }, button.closest(containerSelector));
      }
    });
    
    // или, назначаем обработчик клика каждой кнопке индивидуально
    const onClick = function({ currentTarget: t }) {
      this.forEach((n, i) => n.classList[n.contains(t) ? 'toggle' : 'remove'](activeClass));
    }.bind(document.querySelectorAll(containerSelector));
    
    document.querySelectorAll(buttonSelector).forEach(n => {
      n.addEventListener('click', onClick);
    });
    Ответ написан
    Комментировать
  • Почему на другой странице снова хочет пароль?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Потому что в sessionStorage хранятся строки. Т.е., реально сравниваются "true" и true.
    Ответ написан
    1 комментарий
  • Как сократить код используя цикл?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const inputSelector = '#icons_care';
    const checkboxSelector = '.check_care';
    const checkboxCheckedSelector = `${checkboxSelector}:checked`;
    const dataAttr = 'icon';
    const separator = ', ';

    $(document).on('change', checkboxSelector, () => {
      $(inputSelector).val($(checkboxCheckedSelector)
        .get()
        .map(n => $(n).data(dataAttr))
        .join(separator)
      );
    });
    
    // или
    
    document.addEventListener('change', e => {
      if (e.target.matches(checkboxSelector)) {
        const input = document.querySelector(inputSelector);
        const cb = document.querySelectorAll(checkboxCheckedSelector);
        input.value = Array.from(cb, n => n.dataset[dataAttr]).join(separator);
      }
    });
    Ответ написан
    3 комментария
  • Как оптимальнее при клике на кнопки изменять состояния связанных с ними блоков?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const buttonSelector = '.button';
    const blockSelector = '.div';
    const activeClass = 'red';
    
    function toggleBlock(blocks, buttons, button) {
      const index = Array.prototype.indexOf.call(buttons, button);
      blocks.forEach((n, i) => {
        n.classList[i === index ? 'toggle' : 'remove'](activeClass);
      });
    }
    
    
    // обработчик клика делегированный, назначается один раз
    document.addEventListener('click', e => {
      const button = e.target.closest(buttonSelector);
      if (button) {
        const blocks = document.querySelectorAll(blockSelector);
        const buttons = document.querySelectorAll(buttonSelector);
        toggleBlock(blocks, buttons, button);
      }
    });
    
    // или, назначаем обработчик клика каждой кнопке индивидуально
    const buttons = document.querySelectorAll(buttonSelector);
    const blocks = document.querySelectorAll(blockSelector);
    const onClick = e => toggleBlock(blocks, buttons, e.currentTarget);
    buttons.forEach(n => n.addEventListener('click', onClick));
    Ответ написан
    6 комментариев
  • Как добавить кнопки переключения по годам jquery ui datepicker?

    0xD34F
    @0xD34F Куратор тега JavaScript
    А что, если надо было бы сделать 10 кнопок - вы бы под каждую написали отдельную функцию? Нет, так дела не делаются. Уберите id, добавьте кнопкам атрибут, который будет обозначать соответствующий год:

    <input class="date">
    <input class="date">
    <input class="date">

    const yearButton = year => `
      <button
        data-year="${year}"
        class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all"
      >${year}</button>
    `;
    
    $('.date').datepicker({
      showButtonPanel: true,
    }).each(function(i) {
      $(this).datepicker(
        'option',
        'currentText',
        `Today ${yearButton(2015 + i * 2)}${yearButton(2015 + i * 2 + 1)}`
      );
    });
    
    $(document).on('click', '[data-year]', function() {
      $.datepicker._curInst.input.datepicker('setDate', `01/01/${$(this).data('year')}`);
    });
    Ответ написан
    1 комментарий
  • Почему некорректно отрабатывает JSON.stringify?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Всё работает корректно. Свойства, имена которых не являются целыми числами большими или равными нулю, отбрасываются. У вас же массив. Используйте объект.
    Ответ написан
    Комментировать
  • Как создать плоский объект из вложенного?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Рекурсия есть:

    const nestedToPlain = (obj, path = '') =>
      Object.entries(obj).reduce((acc, [ k, v ]) => {
        const newPath = `${path}${path ? '.' : ''}${k}`;
        return Object.assign(acc, v instanceof Object
          ? nestedToPlain(v, newPath)
          : { [newPath]: v }
        );
      }, {});
    
    
    const plain = nestedToPlain(example, 'example');

    или

    const nestedToPlain = (obj, keys = []) =>
      Object.entries(obj).reduce((acc, [ k, v ]) => (
        keys.push(k),
        Object.assign(acc, v instanceof Object
          ? nestedToPlain(v, keys)
          : { [keys.join('.')]: v }
        ),
        keys.pop(),
        acc
      ), {});
    
    
    const plain = nestedToPlain(example, [ 'example' ]);

    Рекурсии нет:

    const nestedToPlain = function(obj, keys = []) {
      const result = {};
      const [ push, pop ] = this;
    
      for (const stack = [ obj ]; stack.length;) {
        const n = stack.pop();
        if (n instanceof Object) {
          Object.entries(n).reverse().forEach(([ k, v ]) => stack.push(pop, v, k, push));
        } else if (n === push) {
          keys.push(stack.pop());
        } else if (n === pop) {
          keys.pop();
        } else {
          result[keys.join('.')] = n;
        }
      }
    
      return result;
    }.bind([ Symbol(), Symbol() ]);
    
    
    const plain = nestedToPlain(example, [ 'example' ]);
    Ответ написан
    1 комментарий
  • Как отфильтровать массив, чтобы значения определённого свойства не повторялись?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const newArr = arr
      .filter(function(n) {
        return !(this[n.country] = this.hasOwnProperty(n.country));
      }, {})
      .map((n, i) => ({ id: i + 1, country: n.country }));

    или

    const newArr = Object.values(arr.reduce((acc, { country }) => {
      acc[0][country] = acc[0][country] || { id: ++acc[1], country };
      return acc;
    }, [ {}, 0 ])[0]);

    или

    const newArr = Array.from(arr.reduce((acc, { country: n }) => (
      acc.set(n, acc.get(n) || { id: -~acc.size, country: n })
    ), new Map).values());
    Ответ написан
    Комментировать
  • Как правильно отфильтровать свойства массива по вхождению (без учета регистра)?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const keys = [ 'firstName', 'lastName' ];
    const values = document.querySelector('input').value.toLowerCase().match(/\S+/g) || [];
    const result = arr.filter(n => keys.some(k => values.some(v => n[k].toLowerCase().includes(v))));
    Ответ написан
    1 комментарий
  • Перебирать заданный массив цветов для svg и текста mouseenter/mouseleave?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Нетривиальная задача

    Тривиальная.

    Добавляем элементам data-атрибуты, которые будут содержать индекс текущего цвета и имя css-свойства, которое соответствующий цвет будет получать в качестве значения:

    <svg
      data-color-index="-1"
      data-color-attr="fill"
      ...

    <span
      data-color-index="-1"
      data-color-attr="color"
      ...

    По mouseenter делаем индексу +1, обновляем значение css-свойства; по mouseleave записываем в css-свойство пустую строку:

    $('svg, span').mouseenter(function() {
      const colorIndex = (+this.dataset.colorIndex + 1) % colors.length;
    
      $(this).css(this.dataset.colorAttr, colors[colorIndex]);
      this.dataset.colorIndex = colorIndex;
    }).mouseleave(function() {
      $(this).css(this.dataset.colorAttr, '');
    });

    Если элементы должны менять цвет одновременно, тогда отдельные data-атрибуты для индексов не нужны, достаточно одной общей переменной. А обработчики событий цепляем к родительскому элементу:

    let index = -1;
    
    $('.demo').mouseenter(function() {
      index = (index + 1) % colors.length;
      updateColor(this, colors[index]);
    }).mouseleave(function() {
      updateColor(this, '');
    });
    
    function updateColor(el, color) {
      $('[data-color-attr]', el).each(function() {
        $(this).css(this.dataset.colorAttr, color);
      });
    }
    Ответ написан
  • Как реализовать функцию, которая суммирует аргументы и может быть вызвана в одном месте многократно?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function sum(...values) {
      const s = values.reduce((acc, n) => acc + n, 0);
      const f = sum.bind(null, s);
      f.valueOf = () => s;
      return f;
    }
    Ответ написан
    1 комментарий
  • Как посчитать количество повторяющихся значений свойств в объекте JS?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Object.entries(Obj).reduce((acc, [ k, v ]) => ((acc[v] = acc[v] || []).push(k), acc), {})

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

    0xD34F
    @0xD34F Куратор тега JavaScript
    - .popup.visible {
    + .item.visible .popup {

    const container = document.querySelector('.container');
    const itemSelector = '.item';
    const activeClass = 'visible';
    const toggleItem = (item, items) =>
      items.forEach(n => n.classList[n === item ? 'toggle' : 'remove'](activeClass));
    
    
    // делегирование, назначаем обработчик клика один раз для всех item'ов
    container.addEventListener('click', function({ target: t }) {
      if (t.matches(itemSelector)) {
        toggleItem(t, this.querySelectorAll(itemSelector));
      }
    });
    
    // или, каждому item'у назначаем обработчик клика индивидуально
    const items = container.querySelectorAll(itemSelector);
    items.forEach(n => n.addEventListener('click', onClick));
    
    function onClick({ target: t }) {
      if (this === t) {
        toggleItem(t, items);
      }
    }
    Ответ написан
    1 комментарий
  • Как убрать все лишние пробелы, js?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.replace(/\s+/g, ' ').trim()
    Ответ написан
    3 комментария