• Как передать значение textarea в переменную с сохранением абзацев используя JS?

    mizutsune
    @mizutsune
    Frontend Developer
    Можно сделать просто через CSS. Добавляем элементу #res свойство white-space c любым из этих значений: pre-wrap или pre-line и переносы строк визуально будут сохраняться.
    Ответ написан
    1 комментарий
  • Как получить значение внутри блока на который нажали?

    mizutsune
    @mizutsune
    Frontend Developer
    Для начала:

    1. ID атрибуты HTML - элементов должны быть уникальными.
    2. Использование вызова функции через onclick в HTML тегах, выглядит так себе.

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

    document.addEventListener("click", ({ target }) => {
        if (target.classList.contains("lk-addapp-ajax-block")) {
          const value = target.querySelector("input").value;
          alert(value);
        }
      });


    Для того чтобы всё работало корректно, придётся добавить в CSS одну строчку с правилом:

    .lk-addapp-ajax-block  * {
            pointer-events: none;
    }


    Это для того чтобы клик попадал именно на родительский блок, а не на дочерние. Хотя это всё можно решить и по другому, но на мой взгляд и этого будет достаточно.
    Ответ написан
    Комментировать
  • Как разбить textarea на массив?

    mizutsune
    @mizutsune
    Frontend Developer
    1. Получаем содержимое textarea.
    2. Используя метод split разбиваем полученное значение на отдельные слова или предложения по разделителю (перенос строки/точка с запятой/запятая/точка/пробел/etc).
    4. Profit.

    Окончательный результат зависит от того => массив каких значений вам нужно получить и в связи с этим, нужно составлять определенные функции, которые будут решать поставленные задачи, при этом нужно учитывать достаточно множество моментов, при которых что-то может пойти не так.

    Несколько примеров

    Пример - №1:

    Задача: Получить простой массив слов, без модификации регистра заглавных букв и без удаления специальных символов, ну и всего остального.

    let value = '   Illusion is the first of all pleasures.   ';
    
    value.split(" ").filter(n => n !== "");


    1. На первом этапе разбиваем строку на массив слов, используя в качестве разделителя пробел.
    2. На втором этапе удаляются пустые значения из массива.

    Результат:

    ['Illusion', 'is', 'the', 'first', 'of', 'all', 'pleasures.']


    Пример - №2:

    Задача: Получить массив слов без специальных символов и прочего.

    let value = `       Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
    sed do eiusmod, tempor et dolore magna aliqua.
    Amet facilisis magna!!! 
    Ornare quam viverra volutpat odio facilisis mauris.    `;
    
    value.split(" ").map(n => n.replace(/[\r\n.,!]/g, '')).filter(n => n !== "");


    1. На первом этапе разбиваем строку на массив слов, используя в качестве разделителя пробел.
    2. На втором этапе удаляем из каждого "слова" точки, запятые и восклицательный знак.

    Результат:

    ["Lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing",
    "elit", "sed", "do", "eiusmod", "tempor", "et", "dolore",
    "magna", "aliquaAmet", "facilisis", "magna", "Ornare", "quam",
    "viverra", "volutpat", "odio", "facilisis", "mauris"]


    Пример - №3:

    Задача: Получить массив предложений из текста.

    let value = " Lorem ipsum. Dolor sit amet. Consectetur adipiscing elit.      ";
    
    value.split(".").map(n => n.trim()).filter(n => n!== "").map(n => `${n}.`):


    1. На первом этапе разбиваем строку на массив слов, используя в качестве разделителя символ точки, так как точка символизирует окончание предложения в тексте. По крайней мере, в большинстве случаев.
    2. На втором этапе обрезаем пробелы вначале и в конце каждого элемента массива.
    3. На третьем этапе избавляемся от пустых значений.
    4. На четвёртом этапе расставляем точки на концах строк, чтобы превратить их в предложения.

    Результат:

    ['Lorem ipsum.', 'Dolor sit amet.', 'Consectetur adipiscing elit.']


    Пример - №4:

    Задача: Разделить строку на части и записать их в массив, используя несколько разных разделителей.

    let value = "Lorem ipsum, tempor magna aliqua. Dolor sit amet? Consectetur! Adipiscing elit.";
    
    value.split(/[,.?!]/).map(n => n.trim()).filter(n => n!== "");


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

    Результат:

    ['Lorem ipsum', 'tempor et dolore magna aliqua', 'Dolor sit amet', 'Consectetur', 'Adipiscing elit']




    Вариантов разделения строки на массив может быть огромное множество.
    Ответ написан
    Комментировать
  • Почему img стоит не по центру button?

    mizutsune
    @mizutsune
    Frontend Developer
    Конечно неплохо было бы добавить кнопке отдельный класс и уже дальше стилизовать кнопку по селектору класса, а не по имени тега. Ну это так, скорее рекомендация.

    А так по поводу вопроса, то можно сделать например вот так:

    button {
      width: 30px;
      height: 30px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    Ответ написан
    5 комментариев
  • Как у input "file" убрать дефолтный значек?

    mizutsune
    @mizutsune
    Frontend Developer
    При создании своих версий input file, input radio, select и прочих нативных элементов, нужно учитывать многие детали, без реализации и настройки которых компонент будет просто красивой свистелкой без полноценного функционала.

    Вот небольшой пример кастомного </input type="file">:



    Тут конечно есть ещё над чем поработать, но основа уже есть.
    Ответ написан
    Комментировать
  • Почему не работает анимация? CSS JS?

    mizutsune
    @mizutsune
    Frontend Developer
    Анимация не работает потому что в переменной --animation-duration скорее всего содержится <число>ms. Если указать только число, то всё будет работать.

    Однако зачем такие calc(var(--animation-duration) * 1ms) сложности? Неужели не проще написать напрямую время анимации или пусть даже в переменной, но без calc() и прочего? Для чего лишние вычисления и прочие операции? Не нужно ничего усложнять.

    Можно написать намного проще.

    Указываем нужное время анимации в переменной:

    --animation-duration: 500ms;

    Используем без всяких наворотов и лишних движений:

    .add-panel_button.sending .svg{
        animation: fly-out-in var(--animation-duration) ease-in-out;
    }


    В скрипте тоже содержится достаточно лишнего кода. Вместо setTimeout можно прослушивать событие animationend на нужном элементе и тогда лишние вычисления станут реально "лишними" и их можно будет удалить.

    addTodoButton.addEventListener("click", () => {
         addTodoButton.classList.add("sending");
         addTodoButton.addEventListener("animationend", e => {
                   addTodoButton.classList.remove("sending");
                   addItem();
              }, { once: true }
         );
    });
    Ответ написан
    1 комментарий
  • Как объединить название объекта и переменную?

    mizutsune
    @mizutsune
    Frontend Developer
    let shop_id = 82;
    data[`SHOPID_${shop_id}`].name_shop;
    Ответ написан
    Комментировать
  • Как сделать двойную стрелочку на Css?

    mizutsune
    @mizutsune
    Frontend Developer
    Если хочется использовать или создавать иконки на CSS, можете посмотреть эту библиотеку: https://github.com/astrit/css.gg

    Там есть CSS версии иконок, например вот двойная стрелочка. Можете найти нужные вам и заодно возможно и поучиться как делать подобное.

    Или гуглить:

    chevron right css
    chevron double right css

    Однако на мой взгляд для таких целей всё же лучше подходят SVG иконки.
    Ответ написан
    Комментировать
  • Как задать положение Tippy.js в зависимости от размера окна?

    mizutsune
    @mizutsune
    Frontend Developer
    Можно попробовать таким образом менять положение:

    const instance = tippy(".target");
    const breakpoint = window.matchMedia("(max-width: 1200px)");
    
    const breakpointChecker = () => {
         if (breakpoint.matches) {
                  instance[0].setProps({
                   placement: "bottom-end"
              });
    
         } else {
              instance[0].setProps({
                   placement: "left-start"
              });
         }
    };
    
    breakpoint.addEventListener("change", breakpointChecker);
    breakpointChecker();


    Библиотека Tippy предоставляет метод setProps, который позволяет менять свойства экземпляра, а значит если воспользоваться этим методом при достижении нужной ширины экрана, можно обновить свойство placement.

    Вместо matchMedia конечно можно воспользоваться resize, но на мой взгляд - matchMedia намного лучше справляется с поставленными задачами.

    Кстати Tippy возвращает массив независимо от того, какой тип селектора используется. Это связано с тем, что функция Tippy может возвращать несколько элементов в зависимости от селектора. Поэтому чтобы вызывать методы у экземпляра, придётся обращаться к нему как к элементу массива, но это конечно если инициализация происходит без использования цикла.

    UPD:

    Если нужна инициализация нескольких тултипов и изменение параметров при определенной ширине экрана, тогда нужного результата можно добиться например так:

    // коллекция тултипов
    const triggers = document.querySelectorAll(".item__right, .item__prc");
    
    triggers.forEach(element => {
         const instance = tippy(element, {
              // ваши настройки
         });
    
         // ширина экрана при достижении которой нужно изменить настройки
         const breakpoint = window.matchMedia("(max-width: 1200px)");
    
         const togglePlacement = status => {
              // селекторы классов используемых тултипов
              const triggerOne = "item__right";
              const triggerTwo = "item__prc";
    
              const { reference: target } = instance;
    
              const isTargetElement = v => Boolean(target.classList.contains(v));
    
              switch (status) {
                   case "update":
                        if (isTargetElement(triggerOne)) {
                             instance.setProps({
                                  placement: "bottom-end"
                             });
                        } else if (isTargetElement(triggerTwo)) {
                             instance.setProps({
                                  placement: "left-start"
                             });
                        }
                        break;
                   case "default":
                        if (isTargetElement(triggerOne)) {
                             instance.setProps({
                                  placement: "left-start"
                             });
                        } else if (isTargetElement(triggerTwo)) {
                             instance.setProps({
                                  placement: "bottom-end"
                             });
                        }
              }
         };
    
         const breakpointChecker = () => {
              if (breakpoint.matches) {
                   return togglePlacement("update");
              } else {
                   return togglePlacement("default");
              }
         };
    
         breakpoint.addEventListener("change", breakpointChecker);
         breakpointChecker();
    });


    Настройки, селекторы и значения свойств placement в функции togglePlacement замените на нужные вам.
    Ответ написан
  • Как создать сетку из фото как в инстаграм?

    mizutsune
    @mizutsune
    Frontend Developer
    Если правильно понял, то можно например вот так:



    Соотношение сторон конечно изменить, если нужно что-то другое, изменив значение в свойстве aspect-ratio или если по каким-то причинам свойство aspect-ratio не подходит, тогда можно воспользоваться старым трюком используя padding-top: 100% на родительском контейнере, а изображению установить абсолютное позиционирование + растянуть на всю высоту и ширину родительского блока.
    Ответ написан
    1 комментарий
  • Каким способом лучше всего менять html код?

    mizutsune
    @mizutsune
    Frontend Developer
    Если макет не слишком сложный, то можно обойтись и медиа запросами.

    Например вот так:



    Плюс минус немного JS для смены класса и прочее, но в основном всю работу выполняет CSS.
    Ответ написан
  • Как изменить цвет лейбла при состоянии input checked?

    mizutsune
    @mizutsune
    Frontend Developer
    Вместо того чтобы пытаться менять стили тега label при состоянии :checked у input, можно использовать для стилизации элемент <span class="color-tabs__text"></span> и добавив для этого элемента - псевдоэлемент, набросать для него дополнительные стили.

    Далее при выборе кнопки, можно менять внешний вид элемента <span class="color-tabs__text"></span> , а также и внешний вид его псевдоэлемента, что собственно говоря очень удобно.

    Пример:

    Ответ написан
    Комментировать
  • Как в зависимости от ширины экрана заменить html код страницы?

    mizutsune
    @mizutsune
    Frontend Developer
    Если по каким-то причинам недостаточно медиа запросов из CSS, тогда можно воспользоваться методом matchMedia.

    Простой пример использования:

    const targetElement = document.querySelector(".target");
    const breakpoint = window.matchMedia("(max-width: 700px)");
    
    const breakpointChecker = () => {
         if (breakpoint.matches) {
              targetElement.textContent = "Apple";
         } else {
              targetElement.textContent = "Orange";
         }
    };
    
    breakpoint.addEventListener("change", breakpointChecker);
    breakpointChecker();


    Однако несмотря на доступность и простоту использования данного подхода, разумеется намного лучше ограничиться использованием медиа запросов из CSS, чтобы не создавать дополнительную нагрузку применяя JavaScript там где можно обойтись без него.

    Вообще современный CSS уже способен решать многие задачи, связанные например с такими вот случаями, когда требуется модификация блока для отображения на декстопе/мобильнике и если раньше приходилось использовать две разные вёрстки того или иного элемента для разных разрешений экрана или добавлять javascript для решения подобных задач, то уже сейчас в большинстве случаев, такой нужды не осталось.

    И всё как бы понятно и хорошо, но всё же есть такие моменты когда использование JS при работе с медиа запросами - оправданно и matchMedia отлично справляется с поставленными задачами, например когда нужно включить/отключить какой-нибудь плагин или произвести какие-нибудь действия, которые невозможно выполнить используя один только CSS.

    Как альтернативу matchMedia, конечно можно использовать событие resize, но в таком случае придётся оптимизировать функцию используемую в обработчике, так как resize имеет свои подводные камни.
    Ответ написан
    Комментировать
  • Как понять, в каком из input'ов был нажат enter?

    mizutsune
    @mizutsune
    Frontend Developer
    const parentContainer = document.querySelector(".inputs");
    
    parentContainer.addEventListener("keypress", event => {
       if (event.target.tagName !== "INPUT") return;
       if (event.key !== "Enter") return;
    
       console.log(event.target.id);
    });
    Ответ написан
    Комментировать
  • Как два совместить свойства background??

    mizutsune
    @mizutsune
    Frontend Developer
    .header {
       background: linear-gradient(180deg, #0d606f 0%, rgba(13, 96, 111, 0) 25.1%), 
                   url("ссылка_на_изображение.jpg") 0 0/100% 100% no-repeat;
    }
    Ответ написан
    1 комментарий
  • Как выбрать все элементы кроме текущего в forEach?

    mizutsune
    @mizutsune
    Frontend Developer
    Варианты решения с помощью делегирования событий:

    Вешаем обработчик клика на корневой элемент и слушаем событие клика. Если клик произошел на элементе с нужным классом, тогда проходим циклом по всем элементам с этим классом, далее удаляем у них "активные" классы и добавляем их текущему элементу:

    const elements = document.querySelectorAll(".value-item");
    const stateClasses = ["value-active", "basic__shadow"];
    
    document.addEventListener("click", ({ target }) => {
       if (!target.classList.contains("value-item")) return;
       elements.forEach(v => v.classList.remove(...stateClasses));
       target.classList.add(...stateClasses);
    });


    Или:

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

    const stateClasses = ["value-active", "basic__shadow"];
    
    document.addEventListener("click", ({ target }) => {
       if (!target.classList.contains("value-item")) return;
       const activeItem = document.querySelector(".value-active");
       activeItem && activeItem.classList.remove(...stateClasses);
       target.classList.add(...stateClasses);
    });


    Варианты решения с помощью цикла forEach:

    const elements = document.querySelectorAll(".value-item");
    const stateClasses = ["value-active", "basic__shadow"];
    
    const toggleActiveElement = element => {
       element.addEventListener("click", () => {
          elements.forEach(n => n.classList.remove(...stateClasses));
          element.classList.add(...stateClasses);
       });
    };
    
    elements.forEach(v => toggleActiveElement(v));


    Или:

    const elements = document.querySelectorAll(".value-item");
    const stateClasses = ["value-active", "basic__shadow"];
    
    const toggleActiveElement = element => {
       element.addEventListener("click", () => {
          document.querySelector(".value-active")?.classList.remove(...stateClasses);
          element.classList.add(...stateClasses);
       });
    };
    
    elements.forEach(v => toggleActiveElement(v));


    Однако у этих двух вариантов есть небольшие минусы и для таких целей как переключение активного класса при клике, хорошо подходит делегирование событий. Но почему в большинстве случаев не стоит использовать цикл для решения подобных задач?

    1. Вы заставляете браузер искать все элементы с определенным классом на странице.
    2. Добавляется обработчик на каждый элемент, хотя возможно пользователь и не кликнет на этот элемент.
    3. addEventListener добавленный через цикл к каждому элементу определенного NodeList - не будет работать на динамически добавленных элементах. Разумеется если не добавить к ним обработчики, после создания, но это конечно так себе работа.

    Возможно есть и другие побочные эффекты и/или минусы у такого решения задачи.

    Обычно добавление обработчиков в цикле используется в связи с недостатком опыта или просто потому что данный способ в той или иной степени решает поставленную задачу и делать по другому тупо нет желания или смысла. Но даже если отказ от подобных решений и является просто напросто экономией на спичках и/или чем-то там ещё, в любом случае лучше использовать инструменты и функции по назначению, а не потому что просто так хочется или "удобно".

    Правда всё же есть исключения когда добавление обработчиков в цикле оправданно и будет наиболее подходящим способом решить задачу чем например через делегирование событий.
    Ответ написан
    Комментировать
  • Как обрезать строку до определенной длины и добавить многоточие?

    mizutsune
    @mizutsune
    Frontend Developer
    Если нужно просто обрезать строку по количеству символов, то этого можно добиться, например одной из этих функций:

    const truncateString = (s, w) => s.length > w ? s.slice(0, w) + "..." : s;
    
    const truncateString = (s, w) => s.length > w ? s.substring(0, w) + "..." : s;


    Пример использования:

    console.log(truncateString("123456789", 5));

    Но в этих двух вариантах есть по крайней мере, один заметный минус. Если после обрезки строки, в конце будет пробел: "123456 789", то выглядеть результат будет так: "123456 ..."

    Это решается достаточно легко. Воспользуемся функцией .trim() и в итоге, выше описанные функции, будут выглядеть так:

    const truncateString = (s, w) => s.length > w ? s.slice(0, w).trim() + "..." : s;
    
    const truncateString = (s, w) => s.length > w ? s.substring(0, w).trim() + "..." : s;


    Дополнительные решения

    Если нужно обрезать строку, а также удалить и определенные символы с конца строки(лишние точки, запятые, пробелы и прочее), перед добавлением троеточия, тогда можно сделать вот так:

    const truncateStringByLimitChars = ({ target, limit, pattern, useREGEx = true }) => {
      const ignoredChars = new RegExp(`[${pattern}]+$`, "g");
    
      const truncateString = () => {
        return useREGEx === false
          ? target.substring(0, limit).trim() + "..."
          : target.substring(0, limit).replace(ignoredChars, "").trim() + "...";
      };
    
      return target.length >= limit ? truncateString() : target;
    };


    Пример использования:

    console.log(
      truncateStringByLimitChars({
        target: "1234_______",
        limit: 8,
        pattern: [",", ".", "_"]
      })
    );


    Однако в таком случае - финальный размер строки, может быть намного меньше указанного в лимите, потому что функция удалит с конца строки все "лишние" символы. Хотя в некоторых случаях это может быть полезно.

    К примеру имеется строка: Hello__World. Обрезаем без удаления "лишних" символов до 7 символов:

    let string = "Hello__World",
    
    console.log(string.length > 7 ? string.slice(0, 7).trim() + "..." : string)


    Результат: Hello__...

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

    Возможно такой результат не совсем так плох, но всё же, порой это выглядит не слишком, как-бы, красиво и/или удобно. А вот если удалить лишние символы, после обрезки по лимиту символов, то конечно финальный результат будет выглядеть лучше.

    Однако это ещё не всё и при желании, можно дополнительно улучшить функцию - truncateStringByLimitChars, чтобы она корректно работала с такими строками:

    Hello-World.loooooooong.image.name.sss.123456789.jpg

    BackgroundImage_for__container.with.blog-news.cards.jpg


    Допустим имеется такая строка: "BackgroundImageForContainerWithBlogNewsCards.jpg" - это название изображения, которое выводится в определенном блоке.

    Пример:

    <div>Файл "BackgroundImageForContainerWithBlogNewsCards.jpg" успешно загружен</div>


    Задача: Обрезать эту длинную строку до 15 символов + сохранить расширение файла.

    Можно конечно и не модифицировать функцию, чтобы получить желаемый результат, например склеивая обрезанную строку с полученным расширением файла вне функции truncateStringByLimitChars, но это уже другая история и поэтому всё же модифицируем функцию.

    Модифицированная версия будет выглядеть так:

    const truncateString = configuration => {
         const {
            targetString: target,
            limitWords: limit,
            pattern = [",", ".", "_"],
            useREGEx = true,
            suffix = "...",
            addFileExtension = false
        } = configuration;
    
         const ignoredChars = new RegExp(`[${pattern}]+$`, "g");
    
         const reduceContentByLimitCharset = () => {
              return useREGEx === false ?
                 target.substring(0, limit).trim() :
                 target.substring(0, limit).replace(ignoredChars, "").trim();
         };
    
         const updatedContent = () => {
              const croppedString = reduceContentByLimitCharset();
              const fileExtension = target.slice(target.lastIndexOf(".") + 1);
    
              return addFileExtension === false ?
                 `${croppedString}${suffix}` :
                 `${croppedString}${suffix} .${fileExtension}`;
         };
    
         return target.length >= limit ? updatedContent() : target;
    };


    Использование:

    console.log(
         truncateString({
              targetString: "BackgroundImageForContainerWithBlogNewsCards.jpg",
              limitWords: 15,
              addFileExtension: true
         })
    );


    Результат: BackgroundImage... .jpg


    Есть конечно и другие варианты решения всех этих задач по обрезке строк, но, возможно вышеописанных методов будет достаточно.
    Ответ написан
    1 комментарий
  • Не работают кнопки js. Как исправить?

    mizutsune
    @mizutsune
    Frontend Developer
    Если вам нужны табы, то их можно написать как-то так:



    В итоге можно создавать несколько контейнеров с табами на одной странице, переключать активные классы не только у панелей, но и у кнопок, и возможно дополнить функционал какими-нибудь дополнительными функциями.
    Ответ написан
  • Чем можно заменить a href?

    mizutsune
    @mizutsune
    Frontend Developer
    Правильнее будет сделать кнопкой, то есть тегом </button>. При использовании данного тега есть свои плюсы и одним из них является поддержка фокуса по дефолту, т.е если юзать например </div>, то тогда придётся делать дополнительные телодвижения чтобы кнопка слепленная из тега </div> - корректно принимала на себя фокус, например, с клавиатуры. Да и к тому же более семантично использовать </button> для подобных целей. Хотя можно использовать и тег <input>, но в данной ситуации, он совершенно не к месту.
    Ответ написан
    1 комментарий
  • Как видоизменить буллиты на слайдере Swiper?

    mizutsune
    @mizutsune
    Frontend Developer
    Как поменять цвет активного буллита


    .swiper-pagination-bullets .swiper-pagination-bullet-active {
    // стили для активного буллета
    }


    и как их все вместе немного сдвинуть вниз


    Добавить определенные стили для элемента .swiper-pagination-bullets. Например margin-top или если блок с буллетами имеет абсолютное позиционирование, тогда использовать свойство top.
    Ответ написан
    1 комментарий