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

    0xD34F
    @0xD34F Куратор тега JavaScript
    Бегом гуглить, что такое всплытие событий.
    И как его останавливать.
    Ответ написан
    Комментировать
  • Как исключить из функции .each элементы с классами указанными в масиве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const exclude = [ 'class1', 'class2', 'class3' ];
    
    Array
      .from(document.querySelectorAll('div a'))
      .filter(n => !exclude.some(m => n.classList.contains(m)))
      .forEach(n => n.style.display = 'none');
    Ответ написан
    2 комментария
  • Почему тормозит скрипт спустя несколько событий?

    0xD34F
    @0xD34F Куратор тега JavaScript
    У вас при каждом вызове calendarInit назначаются дополнительные обработчики кликов для prev_month и next_month. То есть, при каждом клике количество обработчиков у вас удваивается. Нажали один раз - к одному существующему добавился ещё один, стало два. Нажали второй раз - каждый из этих двух обработчиков добавил по ещё одному, стало четыре. После третьего клика - стало восемь, после шестого - 64. Как думаете, может это стать причиной торможения?
    Ответ написан
    1 комментарий
  • Как запретить выбор пункта в select, если в другом select такой же пункт уже выбран?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const $select = $('select').change(function() {
      const selected = $(':selected', this).get().map(n => n.value);
      const disabled = $(':disabled', this).get().map(n => n.value);
    
      $select
        .not(this)
        .find('option')
        .prop('disabled', function(i, val) {
          return disabled.includes(this.value) ? val : selected.includes(this.value);
        });
    });

    или

    const selects = [...document.querySelectorAll('select')];
    selects.forEach(n => n.addEventListener('change', onChange));
    
    function onChange() {
      const options = [...this];
      const selected = options.filter(n => n.selected).map(n => n.value);
      const disabled = options.filter(n => n.disabled).map(n => n.value);
    
      for (const n of selects.flatMap(m => m === this ? [] : [...m])) {
        n.disabled = disabled.includes(n.value) ? n.disabled : selected.includes(n.value);
      }
    }
    Ответ написан
    Комментировать
  • Как отобразить содержимое в зависимости от выбора select?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Родительскому блоку дополнительного содержимого добавьте какой-нибудь класс, чтобы к нему напрямую обращаться можно было, типа class="subs", например.

    $('select').change(function() {
      $('.subs [class*="sub"]')
        .addClass('hidden')
        .filter(`.sub${$(this).val()}`)
        .removeClass('hidden');
    });
    
    // или
    
    $('select').change(function(e) {
      const index = ($(e.target).prop('selectedIndex') || Infinity) - 1;
      this.addClass('hidden');
      this.eq(index).removeClass('hidden');
    }.bind($('.subs').children()));

    или

    document.querySelector('select').addEventListener('change', e => {
      const cls = `sub${e.target.value}`;
      document.querySelectorAll('.subs [class*="sub"]').forEach(n => {
        n.classList.toggle('hidden', !n.classList.contains(cls));
      });
    });
    
    // или
    
    document.querySelector('select').addEventListener('change', e => {
      const index = ~-e.target.selectedIndex;
      Array.prototype.forEach.call(
        document.querySelector('.subs').children,
        (n, i) => n.classList.toggle('hidden', i !== index)
      );
    });
    Ответ написан
    6 комментариев
  • Как сделать чтобы в input можно было вводить только цифры кратные 100?

    0xD34F
    @0xD34F Куратор тега JavaScript
    О каком input'е идёт речь, и чему должно быть кратно его значение:

    const input = document.querySelector('input');
    const num = 100;

    Можно исправлять вводимые значения:

    input.addEventListener('change', function() {
      this.value = (this.value / num | 0) * num;
    });

    Или не давать вводить неправильные - блокируем ввод в инпут (атрибут readonly), изменение значения осуществляем с помощью кнопок:

    <button data-step="-1">-</button>
    <button data-step="+1">+</button>

    document.querySelectorAll('[data-step]').forEach(function(n) {
      n.addEventListener('click', this);
    }, e => input.value = +input.value + e.target.dataset.step * num);
    Ответ написан
    Комментировать
  • Замена onmousemove?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Добавляем pointer-events: none; элементу .bigImage - всё окей, никаких скачков.
    Ответ написан
    Комментировать
  • Как скопировать наименования классов всех input элементов в отдельном блоке в массив?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Откуда надо получить классы:

    const inputs = document.querySelectorAll('ol input');

    Получаем уникализированный массив классов:

    const classes = [...new Set(Array.prototype.flatMap.call(
      inputs,
      n => [...n.classList]
    ))];

    Или, получаем всё, что есть:

    const classes = Array
      .from(inputs, n => Array.from(n.classList))
      .flat();
    Ответ написан
    4 комментария
  • Как решить задачу с Promise?

    0xD34F
    @0xD34F Куратор тега JavaScript
    В конструкторе создаём promise, делаем его свойством экземпляра, также делаем свойством экземпляра функцию, разрешающую promise; метод then - вызываем метод then у сохранённого promise, пробрасывая ему полученный параметр, результат вызова кладём на место сохранённого promise:

    class deferred {
      constructor() {
        this.promise = new Promise(resolve => this.resolve = resolve);
      }
    
      then(f) {
        this.promise = this.promise.then(f);
      }
    }

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

    class deferred {
      constructor() {
        this.callbacks = [];
      }
    
      then(f) {
        this.callbacks.push(f);
      }
    
      resolve(val) {
        this.callbacks.reduce((res, f) => f(res), val);
      }
    }
    Ответ написан
    1 комментарий
  • Как манипулировать svg, который подключен через тэг object?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не получается обратиться к элементу по его id.

    А как вы это делаете? Вдруг неправильно? Почему не показали?

    Просто по id (или с помощью любого другого селектора) обращаться нельзя, у внешних SVG отдельное DOM-дерево, оно доступно через свойство contentDocument соответствующего object'а, т.е.:

    const svgDocument = document.querySelector('object').contentDocument;
    const element = svgDocument.querySelector('здесь указываете нужный id или что там вам надо');
    Ответ написан
    Комментировать
  • Как определить событие клика event.target элемента?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Замените click на mousedown. А то сейчас у вас получается так: нажали на выбранный пункт, фокус с .select-list ушёл, и к тому моменту, когда вы отпускаете кнопку мыши, список уже скрылся, соответственно, клик получается по элементу, который был под списком.
    Ответ написан
    Комментировать
  • Как скачать файлы по url?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Нет, так просто не получится - тянуть файлы со сторонних доменов через a[download] нельзя.

    Можно загрузить файл, перегнать его FileReader'ом в data url, и уже в таком виде подсунуть в ссылку. Как-то так.
    Ответ написан
    3 комментария
  • Как пронумеровать список в textarea?

    0xD34F
    @0xD34F Куратор тега JavaScript
    textareaEl.addEventListener('paste', function() {
      setTimeout(() => {
        this.value = this.value.split('\n').map((n, i) => {
          const line = i + 1;
          return `${line}. ${n.replace(RegExp(`^${line}\\. `), '')}`;
        }).join('\n');
      });
    });
    Ответ написан
    1 комментарий
  • Как эмулировать клик по элементу после того, как он отрендерился?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Элемент - представленный в примере - это FileInput (кликать нужно на него, что бы вызвать диалог выбора файлов)

    Нет, ничего у вас не получится. Этот диалог может быть открыт только в результате настоящих действий пользователя (и то не всех: клик, нажатие клавиши - окей; скролл, движение мыши, вызов контекстного меню - нет), а не их имитации. По крайней мере, в Хроме. В Фаерфоксе имитировать можно.
    Ответ написан
  • Как написать такое регулярное выражение?

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

    const imgs = document.querySelectorAll('img[src*="/test/"]');

    UPD. Оказывается, автор вопроса с первого раза не сумел рассказать, чего ему надо. Вынесено из комментариев:

    это не в dom, а в строке

    Всё равно регулярные выражения не нужны. Парсим строку, ищем нужные элементы, получаем их разметку:

    const div = document.createElement('div');
    div.innerHTML = str;
    const imgsStr = ''.concat(...[].map.call(
      div.querySelectorAll('img[src*="/test/"]'),
      n => n.outerHTML
    ));

    или

    const imgsStr = Array
      .from(
        new DOMParser().parseFromString(str, 'text/html').querySelectorAll('img[src*="/test/"]'),
        n => n.outerHTML)
      .join('');

    или

    const imgsStr = Array.prototype.reduce.call(
      document.createRange().createContextualFragment(str).querySelectorAll('img[src*="/test/"]'),
      (acc, n) => acc + n.outerHTML,
      ''
    );

    UPD. Нет, со второго раза тоже не получилось. Всплыли ещё подробности:

    мне нужно удалить из этой строки все картинки, которые...

    Удалить, так удалить:

    const div = document.createElement('div');
    div.innerHTML = str;
    const imgs = div.querySelectorAll('img[src*="/test/"]');
    for (let i = 0; i < imgs.length; i++) {
      imgs[i].outerHTML = '';
    }
    str = div.innerHTML;

    или

    const { body } = new DOMParser().parseFromString(str, 'text/html');
    body.querySelectorAll('img[src*="/test/"]').forEach(n => n.remove());
    str = body.innerHTML;

    или

    const fragment = document.createRange().createContextualFragment(str);
    for (const n of fragment.querySelectorAll('img[src*="/test/"]')) {
      n.parentNode.removeChild(n);
    }
    str = Array.from(fragment.childNodes, n => n.outerHTML || n.nodeValue).join('');
    Ответ написан
    6 комментариев
  • Как определить принадлежность элемента по data value?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function onlyOne({ value, dataset: { group } }) {
      document.querySelectorAll(`[data-group="${group}"]`).forEach(n => {
        n.checked = n.checked && n.value === value;
      });
    }
    Ответ написан
    2 комментария
  • Почему дублируется вывод массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Потому что вы дополняете уже существующую разметку, вместо того, чтобы перезаписывать её полностью - несмотря на то, что при выводе списка вы каждый раз обрабатываете все элементы.

    Замените

    todoList.forEach(function(element) {
      document.getElementById('out').innerHTML += '<p>'+element+'</p>';
    });

    на

    document.getElementById('out').innerHTML = todoList.map(n => `<p>${n}</p>`).join('');
    Ответ написан
    3 комментария
  • Как удалить определённые html теги из строки?

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

    const div = document.createElement('div');
    div.innerHTML = html;
    div.querySelectorAll('a[href*="/test/"]').forEach(n => n.outerHTML = '');
    html = div.innerHTML;

    или

    const { body } = new DOMParser().parseFromString(html, 'text/html');
    body.querySelectorAll('a[href*="/test/"]').forEach(n => n.remove());
    html = body.innerHTML;

    или

    const fragment = document.createRange().createContextualFragment(html);
    fragment.querySelectorAll('a[href*="/test/"]').forEach(n => n.parentNode.removeChild(n));
    html = Array.from(fragment.childNodes, n => n.outerHTML || n.nodeValue).join('');
    Ответ написан
    Комментировать
  • Как сортировать option по атрибуту?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Значения атрибутов - это строки. Надо при сравнении преобразовывать их в числа.

    UPD. Ну и в целом - многословно как-то у вас. Можно же гораздо короче:

    function sort(desc, attr) {
      const select = document.querySelector('#search-sort-field');
      select.append(...Array
        .from(select.children, n => [ n, n.getAttribute(attr) * (desc ? 1 : -1) ])
        .sort((a, b) => a[1] - b[1])
        .map(n => n[0])
      );
    }
    Ответ написан
    1 комментарий
  • Как создать таблицу из массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Куда будем добавлять строки:

    const tbody = document.querySelector('#table tbody');
    
    // или
    
    const [ tbody ] = document.getElementById('table').tBodies;

    Добавляем:

    tbody.innerHTML = arr
      .map(n => `
        <tr>
          <td><a href="${n.link}">${n.city}</a></td>
          <td>${n.country}</td>
        </tr>`)
      .join('');

    или

    for (const n of arr) {
      const tr = tbody.insertRow();
      const a = document.createElement('a');
      a.href = n.link;
      a.text = n.city;
      tr.insertCell().append(a);
      tr.insertCell().textContent = n.country;
    }
    Ответ написан
    Комментировать