Ответы пользователя по тегу JavaScript
  • Что лучше использовать для построения диаграммы?

    sergiks
    @sergiks Куратор тега PHP
    ♬♬
    Отличная библиотека для графиков, особенно интерактивных – d3js

    Готового решения там нет, но есть всё необходимое для сборки такого. Посмотрите галерею примеров.
    И, в частности, donut chart и Pie chart update.
    Ответ написан
    Комментировать
  • Как работает функция изменения положения элемента в массиве?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Чтобы поменять местами, надо:
    1. выдернуть первый,
    2. выдернуть второй,
    3. вставить на новое место первый,
    4. вставить на новое место второй.

    Метод массива .splice() умеет и выдирать и вставлять одновременно. Его аргументы:
    позиция-из-которой, сколько-выдрать, вставить-этого, вставить-ещё, ...
    А возвращает он массив выдранных. Поэтому [0] вернёт первый выдранный элемент.

    Можно расписать вашу функцию подробнее:
    function swap(arr, from, to) {
      // выдёргиваем:
      const A = arr.splice(from, 1)[0];
      const B = arr.splice(to-1, 1)[0]; 
      // -1 т.к. массив стал короче после первой операции
    
      // вставляем
      arr.splice(from, 0, B); // 0 - ничего не вырезаем, только вставляем
      arr.splice(to, 0, A);
    }

    Ещё проще то же выглядит безо всяких splice()
    function swap(arr, from, to) {
      // выдёргиваем-копируем:
      const A = arr[from];
      const B = arr[to]; 
    
      // вставляем-заменяем
      arr[from] = B;
      arr[to] = A;
    }
    Ответ написан
    3 комментария
  • Как найти и изменить динамический элемент в Javascript?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    MutationObserver позволяет следить за изменениями DOM.

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

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Предложу свой велосипед на костылях. Без сортировки!
    const zip = arr => arr
      .reduce((agg, c) => {
        const iR = agg.indexOf(c + 1);
        const iL = agg.lastIndexOf(c - 1);
        if (!!~iR && !!~iL) agg.splice(iL, 2); // закрыли дырку
        else if (!!~iR) agg[iR] = c; // сдвинули границу
        else if (!!~iL) agg[iL] = c; // то же
        else { // вставляем сироту - найти позицию сразу после меньшего
          let pos = 0;
          while (pos < agg.length  &&  agg[pos] < c) pos++;
          agg.splice(pos, 0, c, c); // вставляем дважды
        }
        return agg;
      }, [])
      .reduce((agg, c, i, arr) => {
        if (!(i&1)) agg.push(arr[i+1] === c ? c : [c, arr[i+1]].join('-'));
        return agg;
      }, [])
      .join(', ')
    ;

    Массив границ диапазонов, в нём всегда чётное число элементов.
    Очередное число вставляем в массив: ищем, есть ли его ближайшие соседи слева и справа.
    • Если есть оба, число закрывает «дырку», надо просто убрать этих двух соседей.
    • Если нашёлся только один – заменяем его собой, сдвигая границу.
    • Если ни одного соседа, значит, число пока сирота, вставляем его дважды,
      как будто это и левая и правая граница диапазона.
    Так из первого примера получается [ 0, 5, 8, 9, 11, 11 ]
    Остаётся форматирование. Смотрим только чётные элементы. Если текущий и следующий элементы равны, это «одинокое» число. Если не равны — это диапазон через дефис. И склеиваем через запятую-с-пробелом.

    Учитывая сортированность собираемого массива, можно ускорить, заменив indexOf() и lastIndexOf() на самописный поиск, останавливающийся на элементе, бОльшем или меньшем искомого.

    Fiddle с тестами

    Ответ написан
    2 комментария
  • Объясните в чем тут проблема?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Пользуйтесь консолью – это бесплатно, спортивно, современно!
    console.log(this); // window
    В вашем коде this не принимает значение кнопки, а наследует его из внешнего кода. В данном случае, глобального, поэтому this === window

    Вероятно, вы ожидали, что this будет нажатой кнопкой. Так бы работало без стрелочной функции, если по-старинке передавали function(evt) {}
    Ответ написан
    Комментировать
  • Как получить access_token с правом app_widget?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Виджеты сообществ — документация
    0. Получение ключа доступа
    Для работы с виджетами в сообществе необходимо получить токен сообщества с правом доступа app_widget при помощи события VK Connect: VKWebAppGetCommunityAuthToken в приложении с типом VK Mini Apps.


    Создайте приложение ВК типа VK Mini Apps.

    Понадобится библиотека VK Connect: npm install @vkontakte/vk-connect

    И что-то вроде такого в index.js:
    import connect from '@vkontakte/vk-connect'; 
    
    // Sending event to client
    connect
      .sendPromise('VKWebAppGetCommunityAuthToken', {
        "app_id": 6909581, // id вашего свежесозданного mini App
        "group_id": 1,  // id группы, где вы админ, куда виджет
        "scope": "app_widget"
      })
      .then(data => {
        // Обработка события в случае успеха
        console.log(data);
      })
      .catch(error => {
        //Обработка событияв случае ошибки
      });
    Затем, наверное, webpack'ом билдится готовый скрипт, который подгружается в браузер.

    При этом сам токен вы не получаете, не сохраняете, не копируете. Просто теперь у этого VK Mini App'а вашего есть права на обновление кода виджета в вашем сообществе.
    Ответ написан
    Комментировать
  • Как проверить находится ли пользователь на открытой вкладке?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Есть Page Visibility API (на англ.)

    Оттуда пример кода, который приостанавливает воспроизведение видео, если таб стал неактивным:
    spoiler
    // Set the name of the hidden property and the change event for visibility
    var hidden, visibilityChange; 
    if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
      hidden = "hidden";
      visibilityChange = "visibilitychange";
    } else if (typeof document.msHidden !== "undefined") {
      hidden = "msHidden";
      visibilityChange = "msvisibilitychange";
    } else if (typeof document.webkitHidden !== "undefined") {
      hidden = "webkitHidden";
      visibilityChange = "webkitvisibilitychange";
    }
     
    var videoElement = document.getElementById("videoElement");
    
    // If the page is hidden, pause the video;
    // if the page is shown, play the video
    function handleVisibilityChange() {
      if (document[hidden]) {
        videoElement.pause();
      } else {
        videoElement.play();
      }
    }
    
    // Warn if the browser doesn't support addEventListener or the Page Visibility API
    if (typeof document.addEventListener === "undefined" || hidden === undefined) {
      console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
    } else {
      // Handle page visibility change   
      document.addEventListener(visibilityChange, handleVisibilityChange, false);
        
      // When the video pauses, set the title.
      // This shows the paused
      videoElement.addEventListener("pause", function(){
        document.title = 'Paused';
      }, false);
        
      // When the video plays, set the title.
      videoElement.addEventListener("play", function(){
        document.title = 'Playing'; 
      }, false);
    
    }
    Ответ написан
  • Как узнать элемент с которого начинаются цифры в массиве?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Вот такая колбаса вернёт массив, где только «правильные» числа:
    [10, 20, 30, 50, 235, 3000].filter(n => !!~[1,2,5].indexOf(+n.toString()[0]))
    // результат  [ 10, 20, 50, 235 ]
    Вывод на экран пилите самостоятельно.

    Метод массива filter() оставит только те элементы, для которых функция внутри вернёт true. Функция аргумент (в скобках) применяется по очереди к каждому элементу массива (числу).
    Переводит число в строку, забирает первй символ (первую цифру) и переводит опять в число (оператор +).
    indexOf() ищет полученную первую цифру в массиве допустимых: 1, 2, 5 и возврашает его индекс (0, 1 или 2) или -1, если не найдено.
    Битовое инвертирование ~ из -1 сделает 0. А из любого другого числа (из 0, 1 или 2) – сделает ненулевое число. Два !! это два булевых оператора отрицания. Из аргумента делают true или false. Из 0 получится false, из любого другого true. Таким образом связка !!~ и indexOf() даёт ответ на вопрос найден или не найден?
    Ответ написан
    Комментировать
  • Как получить индексы выделенной подстроки?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    См. как работать с Selection API.

    Метод getRangeAt() вернёт диапазон Range. Выделенных фрагментов может быть и несколько, но в вашем примере понадеемся на единственный getRangeAt(0)

    У объекта диапазона Range есть свойства startOffset и endOffset – то, про что спрашиваете.

    Ответ написан
    7 комментариев
  • Импорт и экспорт объектов в Javascript. В чём проблема?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    попробуйте с webpack
    Ответ написан
    Комментировать
  • Как сделать так что бы шахматная фигура по клику перемещалась на другую ячейку?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно разделить данные и их отрисовку. Массив «состояния» доски: какая фигура в какой ячейке. Пустая клетка – пустая строка. Клетка с королевой – 'Q'. И функция, которая отрисовывает всю доску, исходя из Состояния.

    Для обозначения фигур использовать буквы из шахматной нотации. King = K, Queen = Q, Bishop = B, Knight = N, Rook = R, pawn = p
    Понадобится словарь, где ключу фигуры соответствует символ для его отображения.

    Каждая ячейка кликабельна. Кнопка в себе хранит координаты X и Y – понадобятся в обработчике клика, общем для всех.
    Хранится переменная для предыдущего. Изначально пуста. Если кликнули по фигуре, а «предыдущая» пуста, значит это Первый клик - выбор фигуры для хода.
    Второй клик должен выбрать другую ячейку, куда поставить выбранную ранее фигуру, или отменить выделение, если Второй раз выбрана та же клетка, что в Первый.

    Ответ написан
    7 комментариев
  • Вернуть программу в исходное состояние методом reset?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно пройтись по всем текстовым инпутам в секции и дать им value=""
    function reset() {
      [...document.querySelectorAll('section.main input[type="text"]')]
        .forEach( el => el.value='' )
      ;
    }


    Пара общих замечаний
    • Вместо
      document.getElementsByClassName('budget_day-value')[0]

      лаконичнее document.querySelector('.budget_day-value')
    • Пояснительный текст к каждому input'у семантически корректнее оборачивать в тег <label>, и либо указывать id инпута в атрибуте for="", либо включать инпут внутрь этого лейбла. Так клик по названию поля сделает фокус внутри этого поля.

    Ответ написан
  • Правильно ли я понимаю что такое замыкание?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Чтобы понять и понять правильно, можно прочитать целиком страницу про Closure на Learn JavaScript ru.

    Оттуда:

    Замыкания

    В программировании есть общий термин: «замыкание», – которое должен знать каждый разработчик.

    Замыкание – это функция, которая запоминает свои внешние переменные и может получить к ним доступ. В некоторых языках это невозможно, или функция должна быть написана специальным образом, чтобы получилось замыкание. Но, как было описано выше, в JavaScript, все функции изначально являются замыканиями (есть только одно исключение, про которое будет рассказано в Синтаксис "new Function").

    То есть, они автоматически запоминают, где были созданы, с помощью скрытого свойства [[Environment]] и все они могут получить доступ к внешним переменным.

    Когда на собеседовании фронтенд-разработчик получает вопрос: «что такое замыкание?», – правильным ответом будет определение замыкания и объяснения того факта, что все функции в JavaScript являются замыканиями, и, может быть, несколько слов о технических деталях: свойстве [[Environment]] и о том, как работает лексическое окружение.
    Ответ написан
    Комментировать
  • Перебор массива циклом for с целью обращения ко всем остальным элементам кроме i-го?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно проверять, равен ли очередной кандидат – кликнутому элементу:
    const onClick = event => {
      const nodeList = document.querySelectorAll('.item');
      for (let i=0;  i<nodeList.length; i++ ) {
        nodeList[i].style = (nodeList[i] === event.target ? 'background:red' : 'background:green');
      };
    }


    Лучше не пихать инлайн стили, а обойтись классами:
    .item {background: green } // по умолчанию все зелёные
    .item-red {background: red } // тот самый

    используя classList
    // clickedEl — item, по которому кликнули
    [...document.querySelectorAll('.item')].forEach(el => {
      if (clickedEl === el) el.classList.add('item-red');
      else el.classList.remove('item-red');
    });
    Ответ написан
  • Как сделать, чтобы выполнялось действие при трех активных чекбоксах?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    три любых?
    if ([...checks].filter(c => c.checked).length === 3) {
    Ответ написан
    Комментировать
  • Как чайнику разобраться с массивами в JS?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Тут перебор циклом, но не while() и не for() — может, прокатит?
    // случайные:
    const myArray = [...Array(3)]
      .map(
        row => 
          [...Array(3)]
          .map(
            el => Math.floor(Math.random() * 10)
          )
      )
    ;
    
    // диагональ, где оба индекса равны:
    const diagonal = myArray
      .map(
        (row, rowIndex) => 
          row
          .map(
            (el, elIndex) => rowIndex === elIndex ? 1 : 0
          )
      )
    ;
    Ответ написан
    3 комментария
  • Как выполнять цикл синхронно, если в нем асинхронная функция?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    async / await
    /**
     * асинхрота с запросом. Возвращает Promise
     */
    const doAsyncStuff = (urlIter, urlSite) => new Promise((resolve, reject) => {
      needle.get(urlIter, (err, result) => { // Сама асинхронная функция
        if (err) reject(err);
        $('.product-card__link')
          .each((i, val) => prodLink.push(urlSite + $(val).attr("href")));
    
        resolve();
      })
    })
    
    /**
     * Тот самый цикл
     * @param {number} quanPage число страниц
     */
    const doStuff = async quanPage => {
      for(let i = 1; i <= quanPage; i++) {
        let urlIter = urlSite + i; // Ссылка, которая создается с каждой новой итерацией
        await doAsyncStuff(urlIter, urlSite); // Ждём-с!
      }
    }
    
    doStuff(10);


    Демо:
    Ответ написан
    Комментировать
  • Js скрипт не пропускает форму пока она не заполнена. Как убрать?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    замените (временно)
    if(check){
    на
    if(true || check) { // временно убрали проверку заполнения всех полей. TODO убрать костыль


    или сократите код
    function sub(form_id){
      $("#img_loader").val($("#files").find("img").attr("src"));
      $.ajax({
        type: 'POST',
        url: '/php.php',
        data: $('#'+form_id).serialize(),
        success: function(data) {
          $("#recall_wrapper").html("<p class='title_recall'>Ваш отзыв успешно отправлен</p>");
          setTimeout(() => window.location.href='/recalls_ok.htm', 1000); // перекидывать не сразу, а через 1 сек
        },
        error:  function(xhr, str){
          $("#status__send").text('Возникла ошибка: ' + xhr.responseCode);
        }
      });
    }
    Ответ написан
    3 комментария
  • Как правильно генерировать куски сырого HTML в рамках vue с доступом к другим компонентам vue?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Пока не вижу сложности. Кажется, просто надо разобраться с темплейтами и компонентами:


    Вот компонент FooSearchComponent, в который через props из родителя передаём реактивное свойство foo:
    Vue.component(
      "FooSearchComponent",
      {
        props: ['foo'],
        template: '<div>
          <a
            href="#"
            @click="searchFoo(foo)"
          >
            {{ foo }}
          </a>
        </div>',
        methods: {
          searchFoo: function(search) {
            console.log("searchFoo:", search);
          },
        }
      }
    );


    В его темплейте выводится ссылка, в которой слушается событие клика и по нему вызывается собственный метод searchFoo() в который параметром передаётся свойство (реактивное, извне) foo
    Ответ написан