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

    0xD34F
    @0xD34F Куратор тега JavaScript
    не могу додуматься как сделать когда берется уже не первая буква второго слова а последующие

    Отсортируйте алфавит в соответствие с условием близости букв, а затем обходите отсортированный алфавит и ищите слово, начинающееся на текущую букву.

    Как отсортировать алфавит (точнее - получить отсортированную копию): получаете индекс последней буквы последнего слова, создаёте массив с последней буквой, затем делаете цикл от 1 до размера алфавита, закидываете в массив элементы исходного алфавита с индексами, равными индексу последней буквы +/- текущее значение счётчика цикла. Потом отфильтровываете из массива undefined элементы (ну или делайте соответствующую проверку ещё в цикле, тогда ничего фильтровать не надо) - алфавит готов.

    UPD. Выглядеть это может как-то так:
    const alphabet = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.split('');
    const arr = [ 'нора','дом','аметист','баржа','танк','каток','еж','рак','сом','морж','рога','том','сани','лимон','рыба','кот','собака','море','креветка' ];
    const result = [];
    
    getWord(alphabet);
    
    
    while (arr.length) {
      const lastLetter = result[result.length - 1].split('').pop();
      const lastLetterIndex = alphabet.indexOf(lastLetter);
      let letters = [ lastLetter ];
    
      for (let i = 1; i < alphabet.length; i++) {
        letters.push(alphabet[lastLetterIndex + i], alphabet[lastLetterIndex - i]);
      }
      letters = letters.filter(n => !!n);
    
      getWord(letters);
    }
    
    console.log(arr);
    console.log(result);
    
    function getWord(letters) {
      for (let i = 0; i < letters.length; i++) {
        const letter = letters[i];
        const index = arr.findIndex(n => n[0] === letter);
    
        if (index !== -1) {
          result.push(arr.splice(index, 1)[0]);
          return;
        }
      }
    }
    Ответ написан
    2 комментария
  • Почему добавляется один лишний день в таймер обратного отсчета?

    0xD34F
    @0xD34F Куратор тега JavaScript
    почему-то в таймер добавляется один лишний день

    Не добавляется. Это вы забываете вычесть 1 из того, что возвращает метод getDate - нумерация дней, в отличие от часов, минут или секунд, начинается с 1, а не с 0.
    Ответ написан
    Комментировать
  • Как находить при помощи autocomplete?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Заменить:

    1. val = this.value

      на

      val = this.value.toUpperCase()

    2. if (arr[i].substr(0, val.length).toUpperCase() == val.toUpperCase()) {

      на

      if (arr[i].toUpperCase().includes(val)) {

    3. b.innerHTML = "<strong>" + arr[i].substr(0, val.length) + "</strong>";
      b.innerHTML += arr[i].substr(val.length);

      на

      b.innerHTML = arr[i]
        .split(RegExp(`(${val})`, 'i'))
        .map((n, i) => i & 1 ? `<b>${n}</b>` : n)
        .join('');


    Ответ написан
    Комментировать
  • Как сделать рандомный массив из 40 уникальных элементов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сначала подумал что можно рандомизированный массив засунуть в set...

    Надо наоборот - сначала set, потом массив:

    function randomArr(length, min, max) {
      const values = new Set;
      while (values.size < length) {
        values.add((Math.random() * (max - min + 1) | 0) + min);
      }
      return [...values];
    }
    
    
    const arr = randomArr(40, 1, 100);

    Но вообще, есть и другие методы.

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

    function randomArr(length, min, max) {
      const arr = Array.from({ length: max - min + 1 }, (n, i) => i + min);
      return Array.from({ length }, () => arr.splice(Math.random() * arr.length | 0, 1)[0]);
    }

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

    function randomArr(length, min, max) {
      const arr = Array.from({ length: max - min + 1 }, (n, i) => i + min);
    
      for (let i = arr.length; --i > 0;) {
        const j = Math.random() * (i + 1) | 0;
        [ arr[j], arr[i] ] = [ arr[i], arr[j] ];
      }
    
      return arr.slice(0, length);
    }
    Ответ написан
    1 комментарий
  • Как преобразовать дату формата yyyy-MM-dd HH:mm:ss Z?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Ответ написан
    Комментировать
  • Как поставить условие?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Я так понимаю, это прямое продолжение вашего предыдущего вопроса. Директива, о которой я писал в своём ответе, в числе прочих настроек имеет такую, как infinite-scroll-distance. Она задаёт расстояние от нижней границы прокручиваемого элемента, на котором должен сработать коллбек. Просто указываете сколько вам надо.
    Ответ написан
    Комментировать
  • Как вытащить стили конкретного класса DOM?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Можно попробовать обшарить document.styleSheets:

    const getClassStyles = className =>
      [...document.styleSheets].reduce((styles, { cssRules }) => {
        return [...cssRules]
          .filter(n => n.selectorText === `.${className}`)
          .reduce((styles, { cssText }) => {
            return (cssText
              .match(/[\w\-]+: [^;]+/g) || [])
              .map(n => n.split(': '))
              .reduce((styles, [ k, v ]) => (styles[k] = v, styles), styles);
          }, styles);
      }, {});
    
    
    const styles = getClassStyles('class-name');
    Ответ написан
    Комментировать
  • Как построить html дерево по массиву объектов с дочерними элементами?

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

    Рекурсия. Если в элементе есть непустой массив children, то делаете рекурсивный вызов функции, передавая ей этот массив.

    Можно напрямую создавать элементы:

    const createTreeElement = data =>
      Array.isArray(data) && data.length
        ? data.reduce((ul, n) => {
            const li = document.createElement('li');
            const div = document.createElement('div');
            div.textContent = n.name;
            li.append(div, createTreeElement(n.children));
            ul.append(li);
            return ul;
          }, document.createElement('ul'))
        : '';
    
    
    document.body.append(createTreeElement(data));

    Или собрать соответствующую разметку:

    const createTreeHTML = data =>
      data instanceof Array && data.length
        ? `<ul>${data.map(n => `
             <li>
               <div>${n.name}</div>
               ${createTreeHTML(n.children)}
             </li>`).join('')}
           </ul>`
        : '';
    
    
    document.body.insertAdjacentHTML('beforeend', createTreeHTML(data));
    Ответ написан
    Комментировать
  • Как правильно оформить несколько одинаковых canvas на одной странице?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const images = [
      {
        src: 'https://i.imgur.com/GigS3KR.png',
        translate: [ 50, 50, 500, 20 ],
        rotate: [ 340, 200 ],
        draw: [ 0, 0, 0.95 ],
      },
      {
        src: 'https://i.imgur.com/y3JAe69.png',
        translate: [ 5, 0, 382, 2 ],
        rotate: [ 630, 40 ],
        draw: [ 150, 100, 0.84 ],
      },
      {
        src: 'https://i.imgur.com/v30JIWp.png',
        translate: [ 8, 150, 198, 3 ],
        rotate: [ 500, 450 ],
        draw: [ 0, 0, 0.7 ],
      },
    ].map(n => {
      n.draw.unshift(new Image);
      n.draw[0].src = n.src;
      return n;
    });
    
    const canvases = document.querySelectorAll('.canvas');
    const canvasSize = document.documentElement.clientWidth;
    
    for (const n of canvases) {
      n.setAttribute('width', canvasSize);
      n.setAttribute('height', canvasSize);
    }
    
    let ts0;
    window.requestAnimationFrame(function draw(ts) {
      for (const n of canvases) {
        ts0 = ts0 || ts;
        const dt = ts - ts0;
    
        const ctx = n.getContext('2d');
        ctx.clearRect(0, 0, canvasSize, canvasSize);
    
        for (const { translate: t, rotate: r, draw: d } of images) {
          ctx.save();
          ctx.translate(t[0], t[1] + Math.sin(dt / t[2]) / t[3]);
          ctx.rotate(Math.sin(dt / r[0]) / r[1]);
          ctx.drawImage(d[0], d[1], d[2], canvasSize * d[3], canvasSize * d[3]);
          ctx.restore();
        }
      }
    
      window.requestAnimationFrame(draw);
    });
    Ответ написан
    1 комментарий
  • Зачем использовать >>> над десятичными числами?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Вообще-то, нет гарантии, что операция выполняется над числом. Это может быть что угодно. Собственно, потому тут и применяется побитовый оператор - чтобы гарантировать, что len будет целым числом. А почему применяется именно >>>, а не | или >> - число должно быть не только целым, но и положительным (или, если быть более точным, неотрицательным - 0 тоже окей).
    Ответ написан
    2 комментария
  • Как достать текст label, у чекнутой радиокнопки?

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

    const radioSelector = '.radio_wrap input[type="radio"]';

    Как, имея радиокнопку, можно получить содержимое её label'а:

    const getLabel = el => document.querySelector(`[for="${el.id}"]`).textContent;
    // или
    const getLabel = el => el.nextElementSibling.innerText;
    // или
    const getLabel = el => el.labels[0].innerHTML;

    Получаем, по событию change:

    // назначаем обработчик события каждой радиокнопке индивидуально
    document.querySelectorAll(radioSelector).forEach(function(n) {
      n.addEventListener('change', this);
    }, e => console.log(getLabel(e.target)));
    
    // или, можно сделать делегированный обработчик, где будет проверка, откуда пришло событие
    document.addEventListener('change', ({ target: t }) => {
      if (t.matches(radioSelector)) {
        console.log(getLabel(t));
      }
    });
    Ответ написан
    Комментировать
  • Как правильно задать $(this) в настройках плагина?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Попробуйте заменить

    '.catalog__scrollbarLine'

    на

    $(this).find('.catalog__scrollbarLine')

    или

    $(this).find('.catalog__scrollbarLine')[0]
    Ответ написан
  • Почему мои значения не определены?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Если вы внутри функции определяете переменную с таким же именем, как и у переменной из внешней области видимости, то последняя окажется недоступной. Строка 57 - уберите ключевое слово var.
    Ответ написан
    Комментировать
  • Почему setTimeout не изменяет время в цикле?

    0xD34F
    @0xD34F Куратор тега JavaScript
    setTimeout(show(i), i * 300);

    Вместо того, чтобы передать в setTimeout функцию, вы её вызываете.

    Какие есть варианты исправить косяк:

    1. Оберните вызов своей функции в другую функцию, которая будет передана в setTimeout:

      setTimeout(() => show(i), i * 300);

    2. Выполните привязку параметра:

      setTimeout(show.bind(null, i), i * 300);

    3. Передавайте свою функцию в setTimeout, а параметры, с которыми она должны быть вызвана, укажите отдельно:

      setTimeout(show, i * 300, i);

    4. Перепишите свою функцию так, чтобы она возвращала другую функцию:

      function show(x) {
        return function() {
          // сюда помещаете то, что находится у вас в show сейчас
        };
      }

    Ответ написан
    3 комментария
  • Почему этот код не работает в IE?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не работающая часть
    class NewsLoader {

    https://caniuse.com/#feat=es6-class
    Ответ написан
    2 комментария
  • Как удалить дальнего родителя при клике на потомке?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кто "дальний родитель", и кто "потомок":

    const ancestorSelector = 'селектор дальнего родителя';
    const descendantSelector = 'селектор потомка';

    Если клики по вложенным элементам "потомка" учитывать не надо:

    document.addEventListener('click', ({ target: t }) => {
      if (t.matches(descendantSelector)) {
        const ancestor = t.closest(ancestorSelector);
        if (ancestor) {
          ancestor.remove();
        }
      }
    });

    Если интересуют все клики внутри "потомка", в том числе и по его потомкам:

    document.addEventListener('click', e => {
      const descendant = e.target.closest(descendantSelector);
      if (descendant) {
        const ancestor = descendant.closest(ancestorSelector);
        if (ancestor) {
          ancestor.remove();
        }
      }
    });

    UPD. Наконец-то дождались:

    document.addEventListener('click', ({ target: t }) =>
      t.matches(descendantSelector) &&
      t.closest(ancestorSelector)?.remove()
    );

    document.addEventListener('click', e => {
      e.target.closest(descendantSelector)?.closest(ancestorSelector)?.remove();
    });
    Ответ написан
    Комментировать
  • Как остановить/поставить на паузу typed.js?

    0xD34F
    @0xD34F Куратор тега JavaScript
    <span id="typed"></span>
    <div id="actions">
      <button data-action="start">play</button>
      <button data-action="stop">pause</button>
    </div>

    const typed = new Typed('#typed', {
      typeSpeed: 100,
      loop: true,
      strings: [
        'hello, world!!',
        'fuck the world',
        'fuck everything',
      ],
    });
    
    document.querySelector('#actions').addEventListener('click', e => {
      const { action } = e.target.dataset;
      if (action) {
        typed[action]();
      }
    });
    Ответ написан
    1 комментарий
  • Как правильно задать анимацию небольшого вращения-"покачивания" в canvas?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Ну как бы так:

    const cloud = new Image();
    cloud.src = 'https://avatanplus.com/files/resources/mid/56dc1ba4ba1b81534bcbfb9a.png';
    
    (function draw() {
      const ctx = document.getElementById('canvas').getContext('2d');
    
      ctx.globalCompositeOperation = 'destination-over';
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    
      ctx.fillStyle = 'rgba(0,0,0,0.4)';
      ctx.strokeStyle = 'rgba(0,153,255,0.4)';
      ctx.save();
      ctx.translate(300, 200);
    
      const time = new Date();
      ctx.rotate(Math.sin(time / 500) / 10);
    
      ctx.drawImage(cloud, -300, -200);
      ctx.restore();
    
      window.requestAnimationFrame(draw);
    })();

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

    0xD34F
    @0xD34F Куратор тега JavaScript
    100 * arr.reduce((sum, n) => sum + +n.no_apply, 0) / arr.reduce((sum, n) => sum + +n.count, 0)
    Ответ написан
    Комментировать
  • Почему localStorage передает active только из первого списка, а из последующих игнорирует?

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

    Какие есть варианты решения вашей проблемы:
    • Собирать индексы на всех уровнях вложенности, вместо одного числа будете хранить массив
    • Вместо индексов использовать id (лично мне это видится наиболее предпочтительным вариантом - при изменении структуры меню информация о выбранном пункте останется корректной)
    • Ну и наконец, самый лёгкий и простой способ - воспользоваться методом index соответственно вашей задумке, замените $(this).index() на $('.sub3').index(this) (за подробностями - в документацию)
    Ответ написан