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

    0xD34F
    @0xD34F Куратор тега JavaScript
    Ну, очевидно же - не надо полагаться на чётность счётчика. Да ещё и выглядит оно стрёмно, код-то для обоих случаев почти одинаковый. Можно положить картинки в массив, и на каждом шаге делать ему reverse. И вместо обращения к картинкам непосредственно - обращаться к элементам массива. Типа так.
    Ответ написан
    1 комментарий
  • Как объединить большое количество условий?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сделайте объект: то, с чем сравниваете, будет именами свойств; то, что выводите, будет их значениями; то, что проверяете - ключ, по которому будет извлекаться значение. Если ничего не получили, подставляете дефолтное значение. Типа вот так:

    alert(({
      1: 'b',
      2: 'c',
    })[a] || 'd');

    Если вдруг среди значений будут такие, чьим логическим эквивалентом является false, то извлекайте значение из объекта только в том случае, если ключ существует:

    const obj = {
      1: 'b',
      2: 'c',
      7: null,
      8: NaN,
    };
    const defaultValue = 'd';

    alert(obj.hasOwnProperty(a) ? obj[a] : defaultValue);
    Ответ написан
    Комментировать
  • Как удалить из строки точки, запятые, пробелы и символ %?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.replace(/[\s.,%]/g, '')
    Ответ написан
    Комментировать
  • Выдает Cannot set property при вводе в промте,как устранить?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Раз:

    <div class="budget-value"></div>

    Два:

    budget_value = document.getElementsByClassName('budget_value')[0]

    Три:

    budget_value.textContent = money


    Понятно, да - перепутали подчёркивание с минусом, в результате элемент оказался undefined, и вы этому undefined пытаетесь назначать свойство.
    Ответ написан
    Комментировать
  • Почем время выполения двух промисов последовательно эквивалетно времени паралельного выполнения?

    0xD34F
    @0xD34F Куратор тега JavaScript
    результат времени как при параллельном выполнении

    А почему как? Они у вас выполняются параллельно. Чтобы было последовательно - второй должен создаваться в then первого.

    UPD. Вынесено из комментариев:

    Получается что new Promise( уже запускает на выполнение код? Его можно как то отложить?

    Можно сделать getA и getB функциями, возвращающими промисы - тогда будет как вы хотите:

    const getA = () => new Promise((resolve, reject) => {
        console.time('getA');
        setTimeout(() => {
            console.timeEnd('getA');
            resolve(4)
        }, 6000)
    });
    
    const getB = () => new Promise((resolve, reject) => {
        console.time('getB');
        setTimeout(() => {
            console.timeEnd('getB');
            resolve(2)
        }, 2000)
    });
    
    
    console.time('get sum');
    getA().then(a => {
        getB().then(b => {
            console.log(`result: ${a + b}`);
            console.timeEnd('get sum');
            })
        });


    UPD. Cabac_B недоумевает в комментариях по поводу "выполняются параллельно":

    Среда исполнения JS уже умеет параллельно?

    Ну не буквально же параллельно, и не буквально выполняются - смотрите код, о котором идёт речь. Имелось в виду, что оба промиса ждут своего разрешения одновременно.
    Ответ написан
    5 комментариев
  • Identifier has already been declared как исправить?

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

    let money,
        price,

    Ну пожалуйста, добавьте точку, не хватает точки, добавьте-добавьте-добавьте, чтобы стало так:

    let money,
        price;
    Ответ написан
    1 комментарий
  • Как применять IonRangeSlider только что генерированным полям?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Есть ли что-то типо delegate() для такого случая?

    Нет.

    У вас же наверное есть какое-то событие, возникающее при изменении формы (добавлении новых элементов, удаление существующих и т.п.) - вот в его обработчике и инициализируйте новые слайдеры. На крайняк - в обработчике клика по кнопке добавления новых элементов.
    Ответ написан
  • Почему drag and drop некорректно работает при быстром перемещении?

    0xD34F
    @0xD34F Куратор тега JavaScript
    У вас обработчик mousemove вешается на перемещаемый элемент - естественно, что при выходе курсора за пределы элемента перемещение прекращается. А во втором примере, где всё окей - там обработчик mousemove вешается на document.
    Ответ написан
    1 комментарий
  • Javascript как зациклить вывод дней недели?

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

    const days = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'];
    
    // или
    
    const days = Array.from({ length: 7 }, (_, i) => new Date(1, 0, i)
      .toLocaleString('ru', { weekday: 'long' })
      .replace(/./, m => m.toUpperCase()
    ));

    Зацикливаем вывод:

    for (
      let iDay = 0;
      confirm(`${days[iDay]}. Хотите увидеть следующий день?`);
      iDay = (iDay + 1) % days.length
    ) ;
    Ответ написан
    Комментировать
  • Как найти последний элемент массива с нужный свойством?

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

    "Производительно" далеко не всегда значит "лучше". Бывает так, что производительностью можно пренебречь в пользу краткости и читаемости (шутка, являются ли варианты ниже более читаемыми, вопрос спорный). Код - он не только для компьютеров, но и для людей.

    Вот, смотрите - одна строка вместо шести ваших:

    const lastId = arr.reduce((id, n) => n.glob_id || id, null);
    // или
    const lastId = (arr.filter(n => n.glob_id).pop() || {}).glob_id;
    // или
    const lastId = ([...arr].reverse().find(n => n.glob_id) || {}).glob_id;
    // или
    const lastId = arr.map(n => n.glob_id).filter(Boolean).pop();

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

    let lastId = null;
    for (let i = arr.length; i--;) {
      if (arr[i].glob_id) {
        lastId = arr[i].glob_id;
        break;
      }
    }

    UPD. Наконец-то подъехал метод, позволяющий решить задачу и коротко, и без стояния на голове. И трёх с половиной лет ждать не пришлось:

    const lastId = arr.findLast(n => n.glob_id)?.glob_id;
    Ответ написан
  • Как узнать какой по счёту элемент в dom дереве имеет определённый класс?

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

    const parentSelector = 'div';
    const childSelector = 'p';
    const className = 'there';
    
    const siblingsSelector = `${parentSelector} > ${childSelector}`;
    const elementSelector = `${siblingsSelector}.${className}`;

    Дальше есть варианты:

    const index = Array.prototype.findIndex.call(
      document.querySelectorAll(siblingsSelector),
      n => n.classList.contains(className)
    );

    или

    let index = -1;
    for (
      let el = document.querySelector(elementSelector);
      el;
      index++, el = el.previousElementSibling
    ) ;

    или

    const el = document.querySelector(elementSelector);
    const index = el ? [...el.parentNode.children].indexOf(el) : -1;

    Если вдруг у элемента могут быть другие соседи, не соответствующие childSelector, и они не должны учитываться, то третий вариант не подходит, а во втором надо заменить index++ на index += el.matches(childSelector).
    Ответ написан
    Комментировать
  • Как сделать так, чтобы при прокрутке колеса мыши инициировалось нажатие какое-нибудь клавиши на клавиатуре?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.addEventListener('keypress', function(e) {
      if (e.keyCode === 32) {
        console.log('space pressed');
      }
    });
    
    document.addEventListener('wheel', function(e) {
      const event = new Event('keypress');
      event.keyCode = 32;
      document.dispatchEvent(event);
    });
    Ответ написан
    7 комментариев
  • Как из набора элементов удалить определённое количество из начала и конца?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где элементы находятся, и сколько с какого конца надо удалить:

    const selector = 'div p';
    const removeFromStart = 5;
    const removeFromEnd = 3;

    Удаляем:

    document.querySelectorAll(selector).forEach((n, i, a) => {
      if (i < removeFromStart || i > a.length - removeFromEnd - 1) {
        n.remove();
      }
    });

    Или, если родитель действительно общий, то можно и так:

    document.querySelectorAll([
      `${selector}:nth-child(-n+${removeFromStart})`,
      `${selector}:nth-last-child(-n+${removeFromEnd})`,
    ]).forEach(n => n.outerHTML = '');
    Ответ написан
    Комментировать
  • Заменить все совпадения в тексте на ссылку?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Режете текст на куски регуляркой, соответствующей ссылкам (важный момент: надо поместить всё выражение в скобки, это позволит получить в результирующем массиве и сами разделители - будущие ссылки), обходите полученный массив - если элемент соответствует регулярке, делаете ссылку, нет - оставляете как есть. Типа так.
    Ответ написан
    Комментировать
  • Как сделать ограничение на уменьшение числа в input?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Добавить input'у атрибуты min/max; всем трём элементам добавить общую обёртку (уверен, на странице подобных блоков будет больше одного):

    <div class="counter">
      <button class="minus">-</button>
      <input type="number" min="2" max="17" value="5">
      <button class="plus">+</button>
    </div>

    При обновлении input'а ограничивать новое значение значениями атрибутов min/max (если где-то ограничений быть не должно, то вместо отсутствующих значений атрибутов подставлять +/- бесконечность). Кроме того, неплохо бы обрабатывать пользовательский ввод в input - а ну как кто захочет его напрямую отредактировать, мимо кнопок.

    Как это может выглядеть:

    const updateInput = change => e =>
      $('input', e.delegateTarget).val(function(i, v) {
        const min = this.min || -Infinity;
        const max = this.max || Infinity;
        return Math.max(min, Math.min(max, (v | 0) + change));
      });
    
    $('.counter')
      .on('click', '.minus', updateInput(-1))
      .on('click', '.plus', updateInput(1))
      .on('input', updateInput(0));

    Или, к чёрту jquery:

    const updateInput = change => e => {
      const input = e.target.closest('.counter').querySelector('input');
      const min = input.min || -Infinity;
      const max = input.max || Infinity;
      input.value = Math.min(max, Math.max(min, (input.value | 0) + change));
    };
    
    document.querySelectorAll('.counter').forEach(function(n) {
      n.querySelector('.minus').addEventListener('click', this[0]);
      n.querySelector('input').addEventListener('input', this[1]);
      n.querySelector('.plus').addEventListener('click', this[2]);
    }, [ -1, 0, 1 ].map(updateInput));

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

    document.addEventListener('click', ({ target: t }) => {
      const change =
        t.classList.contains('plus')  ? +1 :
        t.classList.contains('minus') ? -1 :
                                         0;
      if (change) {
        const input = t.closest('.counter').querySelector('input');
        input.value -= -change;
        input.dispatchEvent(new Event('input'), { bubbles: true });
      }
    });
    
    document.addEventListener('input', ({ target: t }) => {
      if (t.closest('.counter')) {
        t.value = Math.min(t.max || Infinity, Math.max(t.min || -Infinity, t.value | 0));
      }
    });

    А ещё можно добавить кнопкам data-атрибуты, указывающие, на сколько должно быть изменено значение input'а, и тогда проверять у кнопок наличие классов будет не надо:

    <button class="minus" data-change="-1">-</button>
    <button class="plus" data-change="+1">+</button>

    document.addEventListener('input', updateInput);
    document.addEventListener('click', updateInput);
    
    function updateInput({ target: t }) {
      const counter = t.closest('.counter');
      if (counter) {
        const input = counter.querySelector('input');
        const min = input.min || -Infinity;
        const max = input.max || Infinity;
        input.value = Math.min(max, Math.max(min, (input.value | 0) + (t.dataset.change | 0)));
      }
    }
    Ответ написан
    Комментировать
  • Анимация скролла к элементу с id, при зафиксированных ссылках?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Надо добавлять к желаемому значению scrollTop текущий scrollTop контейнера, т.е.,

    position = anchor.position().top;

    замените на

    position = anchor.position().top + $('#container').scrollTop();
    Ответ написан
  • Как открыть в лайтбоксе только отфильтрованные фото?

    0xD34F
    @0xD34F Куратор тега JavaScript
    А чем у вас сейчас отфильтрованные изображения отличаются от прочих? Видимостью. Под это дело у jquery есть специальный селектор, :visible. Вот с его помощью и отбирайте следующее изображение, например так.

    UPD. Сразу не заметил, у вас там отфильтрованным изображениям назначается специальный класс - конечно, вместо :visible лучше использовать его (в примере по ссылке выше можно просто заменить одно на другое).
    Ответ написан
  • Как изменить содержимое в кнопке при клике?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const buttonSelector = 'button';
    const getButtons = () => document.querySelectorAll(buttonSelector);

    Можем делегировать обработку кликов по кнопкам:

    document.addEventListener('click', e => {
      if (e.target.matches(buttonSelector)) {
        const buttons = getButtons();
        const texts = Array.from(buttons, n => n.textContent);
        for (const [ i, n ] of buttons.entries()) {
          n.textContent = texts[-~i % texts.length];
        }
      }
    });

    А можем назначить обработчик клика каждой кнопке индивидуально:

    const buttons = getButtons();
    const onClick = () =>
      buttons.forEach(function(n, i) {
        n.innerText = ++i === buttons.length ? this : buttons.item(i).innerText;
      }, buttons.item(0).innerText);
    
    buttons.forEach(n => n.addEventListener('click', onClick));
    Ответ написан
    Комментировать
  • Как удалить второй текст div?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Оборачивайте текст в span'ы - тогда и проблем с удалением не будет.

    Ну или можно воспользоваться знанием того факта, что ваш текст представляет собой отдельные узлы DOM-дерева:

    const div = document.querySelector('.line');
    div.removeChild(div.childNodes[2]);
    
    // или
    
    document.querySelector('.line input').nextSibling.remove();
    
    // или
    
    document.querySelector('.line').lastChild.remove();
    Ответ написан
    1 комментарий
  • Как добавить общие обёртки элементам с одним классом, которые находятся между элементами с другим классом?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const $headers = $('.bf-attr-group-header');
    $headers.each(i => $headers
      .eq(i)
      .nextUntil($headers.get(i + 1))
      .wrapAll('<div class="wrapper">')
    );

    или

    document.querySelectorAll('.bf-attr-group-header').forEach((n, i, a) => {
      const wrapper = document.createElement('div');
      const elems = [];
      for (let el = n; (el = el.nextElementSibling) && el !== a[i + 1]; elems.push(el)) ;
      wrapper.append(...elems);
      wrapper.classList.add('wrapper');
      n.after(wrapper);
    });
    Ответ написан
    Комментировать