Ответы пользователя по тегу JavaScript
  • Уходит вверх контент от GSAP после обновления страницы, как решить?

    scoffs
    @scoffs
    Fullstack | C# | Student
    GSAP не сохраняет последнее положение, поэтому всё улетает.

    Чтобы решить эту проблему, вам нужно сохранить текущее состояние анимации и восстановить его после перезагрузки страницы. Можно хранить в localStorage или sessionStorage.
    import { useEffect, useRef } from 'react';
    import gsap from 'gsap';
    import ScrollTrigger from 'gsap/ScrollTrigger';
    
    gsap.registerPlugin(ScrollTrigger);
    
    export default function HorizontalContent() {
      const itemsRef = useRef(null);
      const triggerRef = useRef(null);
    
      useEffect(() => {
        const items = itemsRef.current;
    
        const savedPosition = sessionStorage.getItem('animationPosition');
        const initialPosition = savedPosition ? JSON.parse(savedPosition) : { translateX: 0 };
    
        const pin = gsap.fromTo(
          items,
          initialPosition,
          {
            translateX: '-300vw',
            ease: 'none',
            duration: 1,
            scrollTrigger: {
              trigger: triggerRef.current,
              start: 'top top',
              end: '2000 top',
              scrub: 0.6,
              pin: true,
            },
          }
        );
    
        ScrollTrigger.addEventListener('refresh', () => {
          // Сохраняем текущую позицию анимации
          sessionStorage.setItem('animationPosition', JSON.stringify({ translateX: pin.progress() * -300 }));
          // Очищаем анимацию
          pin.kill();
          // Восстанавливаем исходное состояние анимации
          pin.progress(0).invalidate().restart();
        });
    
        return () => {
          pin.kill();
        };
      }, []);
    
      return (
        <div className={styles.content}>
          <div className={styles.container}>
            <div ref={triggerRef}>
              <div ref={itemsRef} className={styles.items}>
                <div className={styles.item}>
                  <Efficiency />
                </div>
                <div className={styles.item}>
                  <h3>Section 2</h3>
                </div>
                <div className={styles.item}>
                  <h3>Section 3</h3>
                </div>
                <div className={styles.item}>
                  <h3>Section 4</h3>
                </div>
              </div>
            </div>
          </div>
        </div>
      );
    };
    Ответ написан
  • Как закрывать модальное окно действием назад, избегая возвращения по истории?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Открытие окна не производит смены URL, ты остаешься на той же странице, поэтому достаточно странная необходимость делать закрытие модалки при клике на Назад, но это может выглядеть как-то так
    import { useHistory } from 'react-router-dom';
    
    function ModalComponent() {
      const history = useHistory();
    
      const handleCloseModal = () => {
        // Закрытие модального окна и замена текущего пути новым путем (например, '/')
        history.replace('/');
      };
    
      return (
        <div>
          {/* Ваше содержимое модального окна */}
          <button onClick={handleCloseModal}>Закрыть</button>
        </div>
      );
    }
    Ответ написан
  • Как инвертировать скролл по колесу мыши?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Не это?
    try {
     window.addEventListener("wheel", function(event) {
        if (event.deltaX !== 0) {
            event.preventDefault();
            window.scrollBy(event.deltaX, -event.deltaY);
        }
    });
    }
    catch(e) {
      console.error(e);
    }
    Ответ написан
    Комментировать
  • Почему из-за Suspense в React.js(ts) не срабатывает onLoadedData на видео?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Возможно, что видео не срабатывает или срабатывает не всегда, потому что оно еще не загружено на момент первого рендеринга компонента. Из-за этого обработчик может пропустить событие onLoadedData.

    // может использовать onCanPlayThrough ? Или onCanPlay / onPlay
    const handleOnCanPlayThrough = () => {
      setLoading(false)
      console.log('Video loaded')
    }
    
    <video
      onCanPlayThrough={handleOnCanPlayThrough}
      // ...
    >
    Ответ написан
    1 комментарий
  • Как сделать пунктирные линии в диаграмме?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Вроде как в chart.js нет такой функции

    Но может тебе поможет что-то типа этого
    <div class="chart-container">
      <canvas id="myChart"></canvas>
      <div class="tooltip-line"></div>
    </div>

    .chart-container {
      position: relative;
    }
    
    .tooltip-line {
      position: absolute;
      display: none;
      width: 1px;
      height: 100%;
      background-color: black;
      opacity: 0.5;
      pointer-events: none;
      border: dashed;
    }

    const chart = new Chart(document.getElementById('myChart'), {
      // Конфигурация графика Chart.js
      // ...
    });
    
    const tooltipLine = document.querySelector('.tooltip-line');
    
    chart.canvas.addEventListener('mousemove', function(e) {
      const rect = chart.canvas.getBoundingClientRect();
      const xPos = e.clientX - rect.left;
      
      tooltipLine.style.left = xPos + 'px';
      tooltipLine.style.display = 'block';
    });
    
    chart.canvas.addEventListener('mouseout', function(e) {
      tooltipLine.style.display = 'none';
    });
    Ответ написан
  • Как отследить когда кеш сбросится?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Может что-то типа этого?

    После вызова self.skipWaiting() в Service Worker можно отправить сообщение об успешном сбросе кеша обратно в клиентскую часть приложения, используя postMessage(). В клиентской части вы можете прослушивать это сообщение и выполнить обновление страницы с помощью location.reload() или другого подходящего метода.

    // Service Worker
    self.addEventListener('message', event => {
        if (event.data && event.data.type === 'SKIP_WAITING') {
            self.skipWaiting();
            event.source.postMessage({ type: 'CACHE_RESET_SUCCESS' });
        }
    });


    // client
    navigator.serviceWorker.addEventListener('message', event => {
        if (event.data && event.data.type === 'CACHE_RESET_SUCCESS') {
            location.reload();
        }
    });


    Либо
    Если вы хотите, чтобы клиентская часть обновляла страницу после сброса кеша, вы можете прослушивать событие controllerchange на объекте navigator.serviceWorker. Когда Service Worker сбрасывается и становится активным контроллером, будет вызвано событие controllerchange, и вы можете выполнить обновление страницы.

    navigator.serviceWorker.addEventListener('controllerchange', () => {
        location.reload();
    });
    Ответ написан
    Комментировать
  • Как добавить класс всем элементам при использовании querySelectroAll?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Для понимания проблемы достаточно вывести element в консоль при querySelectorAll и понять, что это массив. Тогда для присвоения доп. класса надо пройти по этому массиву и добавить этот самый класс.

    let elements = document.querySelectorAll('.advantages__item');
    
    window.addEventListener('scroll', check, false);
    
    function check() {
      if (window.scrollY > 300) {
        elements.forEach(function(element) {
          element.classList.add('show');
        });
      } else {
        elements.forEach(function(element) {
          element.classList.remove('show');
        });
      }
    }

    console.log() сила!
    Ответ написан
    3 комментария
  • Почему на мобильном устройстве при нажатии на ссылку сразу происходит загрузка новой страницы без выполнения JQuery?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Возможно, проблема в том, что в мобильных браузерах и в Web App Telegram код события клика на ссылке выполняется асинхронно. Из-за этого прелоадер не успевает отобразиться перед переходом на следующую страницу.

    Вы можете вмешаться в процесс отправки формы или перехода по ссылке, чтобы показать прелоадер перед переходом. Для этого вы можете использовать событие отправки формы ($('form').submit(...)) или метод window.location.href для перехода по ссылке.

    Пример кода для реализации этой идеи может выглядеть так:
    $(function() {
    
            $('a').click(function(event) {
              event.preventDefault(); // Отменяет переход по ссылке
              var url = $(this).attr('href');
              $(".loader_inner").fadeIn();
              $(".loader").fadeIn();
              setTimeout(function() {
                window.location.href = url; // Переход по ссылке после отображения прелоадера
              }, 400); // Задержка, чтобы прелоадер успел отобразиться
            });
          });
          
          $(window).on('load', function() {
            $(".loader_inner").fadeOut();
            $(".loader").delay(400).fadeOut("slow");
          });


    UPD 31.05.23: Код обновлён
    Ответ написан
    9 комментариев
  • Как установить цель метрики на все партнерские ссылки?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Вам потребуется добавить код, который будет обрабатывать все ссылки с префиксом /go/ и добавлять необходимый JavaScript-код для цели Яндекс Метрики.

    Что-то типа этого:
    function add_yandex_metric_goal() {
        if (is_singular()) {
            global $post;
            $content = $post->post_content;
    
            // Поиск всех ссылок с префиксом /go/
            preg_match_all('/<a href="\/go\/(.*?)"/', $content, $matches);
    
            // Добавление JavaScript-кода для цели Яндекс Метрики к найденным ссылкам
            if (!empty($matches[1])) {
                $goal_code = "ym(83804250, 'reachGoal', 'goshop'); return true;";
                $replacement = '<a href="/go/$1" onclick="' . $goal_code . '"';
                $content = preg_replace('/<a href="\/go\/(.*?)"/', $replacement, $content);
    
                // Обновление контента поста
                $post->post_content = $content;
                wp_update_post($post);
            }
        }
    }
    add_action('wp', 'add_yandex_metric_goal');


    Приведенный код будет искать все ссылки с префиксом `/go/` на страницах постов или страниц WordPress и добавлять необходимый JavaScript-код для цели Яндекс Метрики.

    Убедитесь, что замените 'ym(83804250, 'reachGoal', 'goshop'); return true;' на ваш фактический код цели Яндекс Метрики.

    После добавления этого кода в functions.php и сохранения изменений, все партнерские ссылки с префиксом /go/ на вашем сайте должны быть обработаны и получить нужный JavaScript-код для цели Яндекс Метрики.
    Ответ написан
    3 комментария
  • Как заэкспортировать в js?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Ошибка не в js, а в настройках eslint. Гуглится за 3 секунды.
    https://stackoverflow.com/questions/36367656/eslin...

    // .eslintrc.modules.json
    {
        "extends": "./.eslintrc.json",
        "parserOptions": {
            "sourceType": "module"
        },
    }
    Ответ написан
  • Как оптимизировать js скрипт?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Я бы посоветовал еще отказаться от var и перейти на letи const

    Инициализировать переменные через запятые также не лучшая затея

    Примерно я написал как-то так
    const bannersClick = document.querySelector('.banners__click');
    const bannersInfo = document.querySelector('.banners');
    const bannersClose = document.querySelector('.banners__close');
    
    function addClass(element, className) {
      element.classList.add(className);
    }
    
    function setRightStyle(element, value) {
      element.style.right = value;
    }
    
    function handleClick() {
      addClass(this, 'slideInRight');
      setRightStyle(this, '400px');
      bannersInfo.classList.remove('slideOutLeft');
      addClass(bannersInfo, 'slideInRight');
      setRightStyle(bannersInfo, '0');
    }
    
    function handleClose() {
      bannersInfo.classList.remove('slideInRight');
      addClass(bannersInfo, 'slideOutLeft');
      setRightStyle(bannersInfo, '-410px');
      setRightStyle(bannersClick, '-10px');
    }
    
    bannersClose.addEventListener('click', handleClose);
    bannersClick.addEventListener('click', handleClick);
    Ответ написан
    Комментировать
  • Как убрать приглушение фоновой музыки при воспроизведении тега audio на JavaScript?

    scoffs
    @scoffs
    Fullstack | C# | Student
    У меня пока возникает вопрос зачем это делать, если это вполне логичное поведение.

    И вроде как браузер / API браузера не имеет контроля над громкостью. Это связано с ограничениями безопасности и конфиденциальности браузеров (предотвращения возможности злоумышленниками записи или слежки за пользователями через звуковые данные)

    Возможные шаги решения / компромиссы:
    • Убедитесь, что ваши звуковые файлы имеют подходящую громкость
    • Используйте более качественные аудиоформаты. Некоторые форматы, такие как MP3, могут звучать более тихо или менее четко при одинаковых настройках громкости. Попробуйте использовать форматы с более высоким качеством звука, такие как WAV или FLAC
    • Попробуйте изменить уровень громкости настройками звука на устройстве пользователя. В некоторых случаях, пользователь может установить громкость фоновой музыки на более высокий уровень, чтобы сделать ее более заметной

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

    scoffs
    @scoffs
    Fullstack | C# | Student
    Тут как посмотреть:
    • Если вы планируете добавлять новые языки или обновлять переводы регулярно, может быть полезно хранить файлы на бэкэнде. Это обеспечит более гибкую систему управления переводами и обновлениями без необходимости изменения клиентского кода.
    • Если содержимое переводов является конфиденциальным или чувствительным, вынос файлов на бэкэнд может предоставить дополнительные меры безопасности
    • Если вы хотите использовать кэширование для оптимизации производительности, хранение JSON файлов на бэкэнде позволит вам настроить соответствующие заголовки кэширования для HTTP-ответов, что снизит нагрузку на сервер и ускорит загрузку переводов
    Ответ написан
    1 комментарий
  • Как вывести по умолчанию массив в autoComplete.js?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Оно?
    new autoComplete({
      data: {
        src: ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'],
      },
      resultsList: {
        render: true, // Отобразить элементы массива по умолчанию
      },
    });
    Ответ написан
    Комментировать
  • Как создать базу данных и связать с JAVASCRIPT?

    scoffs
    @scoffs
    Fullstack | C# | Student
    У меня есть мелкий проект
    Там MERN стек - MongoDB / Express / React / NodeJS, может поможет

    А ванильный пример будет выглядеть как-то так:

    Для начала надо вообще сказать монго на пк, а потом и в проект
    npm install mongodb

    Потом можно в папке server подключиться к БД
    const { MongoClient } = require('mongodb');
    
    const url = 'mongodb://localhost:27017'; // URL базы данных
    const dbName = 'mydatabase'; // Имя базы данных
    
    const client = new MongoClient(url);
    
    async function connectToDatabase() {
      try {
        await client.connect();
        console.log('Connected to the database');
        return client.db(dbName);
      } catch (error) {
        console.error('Error connecting to the database:', error);
      }
    }
    
    module.exports = connectToDatabase;


    Делаем базовые маршруты
    const express = require('express');
    const connectToDatabase = require('./db'); // Путь к файлу подключения к базе данных
    
    const app = express();
    app.use(express.json());
    
    // Маршрут для сохранения данных в базу данных
    app.post('/data', async (req, res) => {
      const { email, phoneNumber, fullName } = req.body;
    
      try {
        const db = await connectToDatabase();
        const collection = db.collection('data'); // Имя коллекции
    
        const result = await collection.insertOne({
          email,
          phoneNumber,
          fullName,
        });
    
        res.status(201).json(result.ops[0]); // Отправить сохраненный документ обратно клиенту
      } catch (error) {
        console.error('Error saving data to the database:', error);
        res.status(500).json({ error: 'An error occurred' });
      }
    });
    
    app.listen(3000, () => {
      console.log('Server listening on port 3000');
    });


    Ну и базовая разметка
    <form action="/data" method="POST">
      <label for="email">Email:</label>
      <input type="email" id="email" name="email" required>
      
      <label for="phoneNumber">Phone Number:</label>
      <input type="tel" id="phoneNumber" name="phoneNumber" required>
      
      <label for="fullName">Full Name:</label>
      <input type="text" id="fullName" name="fullName" required>
      
      <button type="submit">Submit</button>
    </form>


    require лучше заменить на import (в packages.json указать надо "type": "module")
    Ответ написан
    3 комментария
  • Как получить массивы объектов с одинаковыми ключами из другого массива объектов?

    scoffs
    @scoffs
    Fullstack | C# | Student
    Кажется тебе тут поможет `reduce`
    const array = [
      {id: 1, name: 'Test_1'},
      {id: 2, name: 'Test_2'},
      {id: 3, name: 'Test_3'},
      {id: 4, name: 'Test_1'},
      {id: 5, name: 'Test_2'}
    ];
    
    const groupedArrays = array.reduce((result, obj) => {
      // Проверяем, существует ли уже массив с данным значением name
      const existingArray = result.find(arr => arr[0].name === obj.name);
      
      // Если такой массив уже существует, добавляем текущий объект в него
      if (existingArray) {
        existingArray.push(obj);
      } else {
        // Если такого массива еще нет, создаем новый массив с текущим объектом
        result.push([obj]);
      }
      
      return result;
    }, []);
    
    // Печатаем результат
    groupedArrays.forEach(arr => {
      console.log('____');
      console.log(arr);
    });
    Ответ написан