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

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Вариантов, на самом деле, несколько.
    С учётом что у Вас jQuery, то предложу следующее:
    Заведите переменную, отвечающую за состояние формы.
    Состояние будет определять какую группу контролов показывать через css, например по data-атрибуту. (Ведёт к разбуханию CSS. Лучше тоглить JSом по соответствующему селектору);
    Таким образом, например, можно менять значение дата атрибута на самой форме, а значение атрибута будет значение состояния.
    Каждой группе контролов назначаем обработчик, который будет менять состояние на следующее. (В примере через делигирование).

    Собственно.. ПРОФИТ.

    Набросок примера. На работоспособность не проверял:
    .form__input_stage{
          display: none;
        }
        
        .form[data-stage="1"] .form__input_stage[data-stage="1"]{
          display: block;
        }
    
        .form[data-stage="2"] .form__input_stage[data-stage="2"]{
          display: block;
        }

    <form action="" class="form" data-stage="1">
          <input type="text" class="form__input">
          <input type="text" class="form__input form__input_stage" data-stage="1">
          <input type="text" class="form__input form__input_stage" data-stage="2">
    </form>

    var form = document.querySelector('.form');
        form.addEventListener('change', formChangeHandler);
    
        function formChangeHandler(evt){
          var stage = Number(evt.target.dataset.stage);
          var nextStage = stage+1;
          form.dataset.stage = nextStage;
        }
    Ответ написан
    Комментировать
  • Что позволяет записывать в функции статические методы?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Воспользуюсь спорным штампом и отвечу: так происходит, потому что "в JS всё - объект". Соответственно, как объектам, мы можем назначать свойства.
    С примитивами всё несколько сложнее. Мы вроде бы тоже можем назначить им свойство, но это иллюзия. Когда мы делаем подобное с примитивами, например строкой, то вызывается её конструктор String(), а когда операция "под капотом" завершается, то мы снова получаем примитив, таким образом, ошибки назначения свойства не возникает, но и свойство недоступно.

    Это если сжато.
    Подробно объяснять не быстро. Скорее всего Вам тут посоветуют почитать документацию, спецификацию. Я предложу почитать серию книг You Dont Know JS. Можно нагуглить перевод многих глав из этой серии книг.
    Ответ написан
    Комментировать
  • Можно ли сделать сетеры для методов массива?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    <классическое отступление>
    Делать подобные вещи, а так же переопределять прототип - считается плохим тоном. 
    Написание, как Вы выразились "обёртки" - лучший выбор.
    </классическое отступление>


    Гетеры и сетеры это по своему существу - методы.
    .push() - тоже метод.
    Вы хотите установить метод для метода? Крайне маловероятно.

    Ближайшее что Вам, гепотетически, может помочь - Proxy или декораторы
    Ответ написан
  • Стрелочную или обычную функцию использовать?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Раз уж пошла такая пьянка, то лучше будет так:
    var cityBox = document.querySelector("#cityBox");
    var anotherCity = document.querySelector("#another");
    anotherCity.addEventListener("click", anotherCityHandler);
    
    function anotherCityHandler() {
      cityBox.innerHTML = '<p class="city__title">Choose a city:</p><input type="text" class="city__input input" placeholder="Enter city" />'
    }


    Чем лучше:
    • Сохраняете ссылку на элемент в переменную, таким образом меньше обращений к DOM (Одна из самых медлительных операций)
    • Определеяете функцию и добавляете обработчик по ссылке. Такой подход позволяет воспользоваться методом removeEventListener, а так же переиспользовать функцию отрисовки дополнительного инпута.


    Так же стоит задуматься чтобы вместо innerHTML использовать append, а элементы генерировать в отдельной функции.

    Использовать стрелочную функцию или обычную, в данном случае, практически без разницы, тем не менее, предложу пользоваться обычной, так как у Вас нет необходимости в стрелочной.
    Критерий "мне эта больше нравится, потому что она красивее" - плохой критерий.
    И, к сожалению, без пруфов и 100% уверенности в следующих словах: обычная функция для движка будет проще.
    Ответ написан
    Комментировать
  • Почему не работает функция в браузере?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    function nameOfFunction () {
    alert (2+3);
    }

    nameOfFanction(); // опечатка.

    Вам редактор должен был предлагать автодополнением название Вашей функции (при попытке вызвать её), если бы Вы его использовали, то не было бы опечатки.
    Так же рекомендую научиться пользоваться линтером. (ESLint)
    Ответ написан
    Комментировать
  • Как скачать Blob при помощи jQuery.ajax?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Исходя из наличия тэга jQuery в вопросе:
    По умолчанию jQuery не умеет в бинарный запрос.
    Нужно подключить дополнительную мини либу: jQuery binnary transport
    Пример скачивания можно найти по ссылке.
    Пример загрузки зависит от конкретной задачи. Но если в общих чертах, то вот так:
    $.ajax({
        url: url,
        type: 'POST',
        processData: false,
        data: arrayBuffer,
        headers: {
            "content-length": arrayBuffer.byteLength
        }
    });

    arrayBuffer - blob или, например, результат считывания файла readAsArrayBuffer
    Ответ написан
    Комментировать
  • Почему в плагине dataTable не работает сортировка с буквой Ё?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Решение здесь и сейчас - не использовать Ё.
    В код либы не заглядывал, но, скорее всего, дьявол кроется в том, что asci код символа ё больше других в алфавите.
    "деёж".charCodeAt(0) // д -1076
    "деёж".charCodeAt(1) // е - 1077
    "деёж".charCodeAt(2) // ё - 1105
    "деёж".charCodeAt(3) // ж -1078

    Если не использовать Ё - не вариант, то, насколько я помню, в этом плагине можно указывать сортировку по дата атрибутам.
    Таким образом, Вы сами можете определить значения, на основе которых будет осуществляться сортировка, где "е" и "ё" будут идти последовательно или иметь одинаковй вес, а потом натравить dataTable на эти значения.
    Ответ написан
    Комментировать
  • Как в slick-slider сделать 2 уровень картинок?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Документацию не просто так пишут :)
    Читайте внимательнее.
    Вас интересует параметр "rows" при инициализации.
    CryNet привёл вам даже пример на кодпене.
    $('#slick1').slick({
    		rows: 2, // <-- вот что Вам нужно.
    		dots: false,
    		arrows: true,
    		infinite: true,
    		speed: 300,
    		slidesToShow: 6,
    		slidesToScroll: 6
    });
    Ответ написан
    2 комментария
  • Как лучше реализовать выпадающую шторку на сайте?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Сделать у шторки footer, в виде некой "риски". И на неё уже вешать обработчик свайпа.
    5d55734acb356595239824.png
    Ответ написан
    Комментировать
  • Как сделать загрузку изображения с компьютера пользователя?

    MrDecoy
    @MrDecoy Куратор тега CSS
    Верставший фронтендер
    Комментировать
  • Как привязать точки(dots) к слайдам на самописном слайдере?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    У вас dot - пустой массив. Вы инициализируете эту переменную до того, как в разметке появляются li.dots и далее Вы в функции используете этот пустой массив. Соответственно, elem[index], где elem это dot нулевой длины, выдаёт undefined, так как elem[index] не существует.
    Ответ написан
  • Проблема со slick slider, как переставить кнопки prev и next в другой контейнер?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    А ещё Вы можете сверстать кнопки отдельно и при инициализации слайдера указать, что эти html элементы будут кнопками для слайдера.
    Давно им не пользовался, но, если не ошибаюсь, то нужно просто, например, в prevArrow указать селектор элемента(элементов) которые будут отвечать за перелистывание на предыдущий слайд для данного слайдера.
    Документация это подтверждает:
    prevArrow
    Type: string (html|jQuery selector) | object (DOM node|jQuery object)
    Ответ написан
    Комментировать
  • Как такое сверстать и сделать анимацию?

    MrDecoy
    @MrDecoy Куратор тега CSS
    Верставший фронтендер
    WEB Audio API. А графики можете как сами строить, так и какой-нибудь библиотекой. Примеры Вам уже привели выше.
    https://habr.com/ru/post/210422/
    Ответ написан
    Комментировать
  • Как сократить код?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    Вариантов на самом деле хоть отбавляй.
    Ну, начнём с того, что использовать селектор по ID это контрпродуктивно и ведёт к хаосу и разбуханию.
    Судя по Вашему коду, Вы хотите чтобы каждая следующая кнопка показывала соответствующую по индексу картинку из коллекции.
    В таком случае, можно опираться на индексы.
    То есть:
    1) назначаем кнопкам уникальный класс
    2) матчимся в селекторе на этот класс,
    3) назначаем обработчик клика,
    4) в обработчике клика получаем индекс данной кнопки,
    5) подставляем индекс в коллекцию, чтобы вытащить нужный путь до картинки.
    6) Профит.

    Но, выше уже сказали про делегирование. Чем оно лучше чем то , что я выше описал? У вас всего один обработчик, на один элемент - контейнер кнопок. Так как события всплывают, то можно перехватывать на родительском элементе всплывшее событие клика и запускать вышеуказанную обработку. Таким образом, один обработчик лучше чем много, согласитесь :-) И не нужно париться чтобы довешивать обработчики на динамически сгенерирванные кнопки.
    Итак, пример:

    HTML:
    <div id="main__display"></div>
    <div class="images-controls">
        <button type="button" class="images-controls__btn">1</button>
        <button type="button" class="images-controls__btn">2</button>
        <button type="button" class="images-controls__btn">3</button>
        <button type="button" class="images-controls__btn">4</button>
    </div>


    JS:
    var collection = [
        "https://via.placeholder.com/100",
        "https://via.placeholder.com/200",
        "https://via.placeholder.com/300",
        "https://via.placeholder.com/400",
    ]
    
    // Добавляем обработчик на контейнер кнопок
    $('.images-controls').on('click', function(evt){
        // evt - Объект события.
        // Элемент, на котором произошёл клик:
        var target = evt.target; 
    
        // проверяем, есть ли у этого элемента класс, присущий нашим кнопкам:
        if(target.classList.contains('images-controls__btn')){
            var btnIndex = $('.images-controls__btn').index(target); // Находим индекс этой кнопки из массива всех кнопок.
            // Рендерим картинку, извлекая путь до картинки по индексу кнопки из коллекции
            $("#main__display").html(
                '<img src="' + collection[btnIndex] + '">'
            )
        }        
    });
    Ответ написан
    Комментировать
  • Как объединить несколько событий в JS?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    В предложенном варианте Виктор Л, по крайней мере у меня, есть баг, что в селекте появляются лишние года. Модифицировал код. Кораблик движется по клику как на точку, так и на выбор из выподающего списка, аналогично и текст меняется как при клике на точку, так и на выбор в селекте.

    1) Модифицируем селект, чтобы в options value были года.
    <select class="main-select " id="select">
      <option value="2001">2001</option>
      <option value="2002">2002</option>
      <option value="2003">2003</option>
      <option value="2004">2004</option>
      <option value="2005">2005</option>
      <option value="2006">2006</option>
      <option value="2007">2007</option>
      <option value="2008">2008</option>
    </select>


    Модифицируем генгерацию кружков, добавляем к каким годам они относятся в дата-атрибут.
    svg.innerHTML += Array(count).fill(0).map((e, i) => {
          let len = seg * (i + 1), p = track.getPointAtLength(len);
          return "<g transform=translate("+[p.x, p.y]+") class"+(i?'':'=active')+">" +
                 "  <circle data-len="+len+" r=11 data-year="+(2001+i)+"></circle>" +
                 "  <rect rx=5 ry=5 x=-20 y=16 width=40 height=19></rect>" +
                 "  <text y=30 id='"+(2001+i)+"'>"+(2001+i)+"</text>"+
                 "</g>";
        }).join('');
    
    // Другой код без изменений
    
    // Модифицируем обработчик клика по кружку
    circles.forEach(c => c.onclick = e => {
          circles.forEach(c1 => c1.parentNode.classList.toggle('active', c === c1));
          targets.push(+c.dataset.len);
          let root = c.parentElement;
            let text = root.lastChild;
            let circleYear = c.dataset.year; // получаем значение года из дата атрибута кружка, по которому произошёл клик.
          let div = document.getElementById('text');
              div.innerHTML = promoText[text.textContent].text;
            var x = document.getElementById('select');
            x.value = circleYear; // - устанавливаем значение селекта на то, которое совпадает с дата атрибутом данного кружка.
            $(x).niceSelect('update'); // Так как используется библиотека niceSelect, а значение мы поменяли на исходном селекте, то обновляем niceSelect.
            // x.options[x.selectedIndex].text= text.textContent; - код, который создавал, по-моему мнению, баг.
             
        });
        
        //Select
        $(document).ready(function() {
            $('select').niceSelect();
    
    // Добавялем обработчик на изменение селекта, чтобы кораблик двигался, текст менялся. По факту, просто тригерим клик программно по кружку, у которого совпадающий по году дата-атрибут.
            $('#select').on("change", function () {
                $('circle[data-year="' + this.value + '"]').trigger('click');
            });
        });
    Ответ написан
    2 комментария
  • Засунуть код всех плагинов в один файл?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    1. Если Вы верстаете\подключаете скрипты под обычную вёрстку или на какую-нибудь CMS, условно Битрикс, то считается хорошей практикой собирать все подключаемые библиотеки в отдельный файл, называть его, например, libs.js или assets.js или vendors.js(приоритетный вариант), минифицировать код этого файла и уже его подключать к странице. Разумеется делается это по хорошему не вручную, а с помощью какого-нибуть таск раннера, например gulp.
    2. Если Вы знаете что за библиотеки Вы используете и предусмотрели пересечение глобальных переменных(что бывает весьма не часто), например, вызов функции $, то конфликтов быть не должно.


    P.s. не забудьте, что на каждой отдельно взятой странице могут быть не нужны все библиотеки, которые Вы используете на всём сайте и подключение такого монстра сильно и бесполезно увеличит вес странице со всеми вытекающими. Поэтому, если какая то библиотека используется только на одной странице, то будет правильнее исключить её из сборки и подключить к этой странице отдельно.

    В современном же, более подвинутом, фронтенде, используются инструменты сборки(Webpack) с помощью которых js код пишется в разных файлах помодульно. Сборщик строит граф зависимостей ваших js модулей и генерирует нужный файл(бандл) который и нужно подключить(или асинхронно подгружает модули по требованию - это идеальный вариант).
    Ответ написан
    Комментировать