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

    @askhat
    Не благодари

    const monthToInt = val => {
      val = val.toLowerCase();
      switch (true) {
        case !!val.match(/^янв/):  return 0;
        // TODO добавить больше кейсов
      }
    }
    
    const dateFromLocaleString = date =>
      new Date(
        ...date
          .split(" ")
          .reduce(
            (acc, val) =>
              (acc = [val.match(/\D/) ? monthToInt(val) : parseInt(val), ...acc]),
            []
          )
      )
    
    dateFromLocaleString('07 янв 2019')
    Ответ написан
    Комментировать
  • Чем заменить функцию .map() в моем случае?

    @askhat
    На вопрос ответил автор вопроса, я в свою очередь попытаюсь объяснить что произошло.

    Рендер в реакте всегда идёт по наименее трудозатратному пути, а именно вычисляет дельту (разницу) между новым стейтом и предыдущим, если таковой имеется. Например:

    class TodoList extends React.Component {
      state = {
        todos: [
          'Commit',
          'Push'
        ]
      }
      render() {
        return <ul>
          {this.state.todos.map(item => {
            return <li>{ todo }</li>
          }
        </ul>
      }
    }


    Если стейт компонента изменится, скажем при добавление элемента в начало списка todos, так что он станет таким:

    const todos = [
      'Init',
      'Commit',
      'Push'
    ]


    Реакт вычислит два древа VirtualDOM:

    // Начальный стейт
    <ul>
      <li>Commit</li>
      <li>Push</li>
    </ul>
    // Добавлен элемент
    <ul>
      <li>Init</li> // <- разница начинается здесь и до конца древа
      <li>Commit</li>
      <li>Push</li>
    </ul>


    Здесь выполняется работа которой можно было бы избежать. К примеру если бы элемент был добавлен в конец списка:

    const todos = [
      'Commit',
      'Push',
      'Merge'
    ]


    То реакт получил бы на сравнение другие два древа элементов:

    // Начальный стейт
    <ul>
      <li>Commit</li>
      <li>Push</li>
    </ul>
    // Добавлен элемент
    <ul>
      <li>Commit</li>
      <li>Push</li>
      <li>Merge</li> <- разница начинается здесь, от начала и до сих по ничего не менялось
    </ul>


    Дельта этих двух списков меньше, а значит и работы нужно сделать меньше.

    Совершенно очевидно что <li>Commit</li> и <li>Push</li> не менялись, однако реакт недостаточно умён чтобы это понять. Чтобы помочь ему следует воспользоваться специальным пропом key={}. Он может быть значением любого типа, единственно требование — значение должно стабильно идентифицировать соответствующие данные.

    Если бы компонент выглядел так:

    class TodoList extends React.Component {
      state = {
        todos: [
          { id: 0, text: 'Commit' },
          { id: 1, text: 'Push' }
        ]
      }
      render() {
        return <ul>
          {this.state.todos.map(item => {
            return <li key={todo.id}>{ todo.text }</li>
          }
        </ul>
      }
    }


    То добавление элемента в начало массива, породило бы следующий стейт:

    const todos = [
      { id: 2, text: 'Init' },
      { id: 0, text: 'Commit' },
      { id: 1, text: 'Push' }
    ]


    И, снова, два древа элементов:

    // Начальный стейт
    <ul>
      <li>Commit</li> // id 0
      <li>Push</li> // id 1
    </ul>
    // Добавлен элемент
    <ul>
      <li>Init</li> // id 2 новый элемент отобразится в начале
      <li>Commit</li> // id 0
      <li>Push</li> // id 1 
    </ul>


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

    Таким образом использовать индекс в массиве в качестве ключа — не лучшая идея, особенно если массив будет меняться. По той же причине не следует использовать Math.random() в качестве ключа, так вы почти гарантировано будете всегда получать нестабильные идентификаторы.

    Подробнее об этом можно почитать здесь — Reconciliation.
    Ответ написан
    5 комментариев
  • Как деструктуризовать объект без отдельных свойств?

    @askhat
    const { name, email } = obj

    Просто не создавайте идентификатор под это свойство
    Ответ написан
    2 комментария
  • Как пишут frontend на более менее больших проектах?

    @askhat
    Сниппет кода который вы привели, очень похож на общее представление о веб-компоненте. Если класс CategoiesFilter расширит класс React.Component, вам будет нужно реализовать метод render. Тогда вы сможете избавиться от селекторов по заранее написанному html.
    Опционально вы сможете реализовать методы т.н. хуки жизненного цикла, тогда вы получите более тонкий контроль.
    Говорят пользователи Vue используют очень похожий подход к моделированию, но пользуются более гибким синтаксисом рендер функции (они просто пишут html и css.)
    Если речь идёт о более крупных приложениях, часто испозуют redux и mobx. Они реализуют похожие паттерны flux и observable. Но это уже совсем другая история.
    Смысл всех этих технологий в Virtual DOM. Он позволяет не писать все состояния вашего приложения сразу в html, а вычислят его на основе данных в JavaScript и только тогда создавать html наиболее оптимальным образом.
    Ответ написан
    3 комментария
  • XMLHttpRequest или fetch?

    @askhat
    В идеальном мире у вас есть абстракция http клиента в которой вы легко меняете реализацию без изменений в остальном коде
    Ответ написан
    Комментировать
  • Как вывести img в массиве?

    @askhat
    <img v-for="item in menu" :src="item.image"/>
    Ответ написан
    Комментировать
  • Как из строки сделать массив с рандом значениями?

    @askhat
    function uid (alphabet, n) {
      let string = ''
      for (let i = 0; i < n; i++) {
        string += alphabet[Math.floor(Math.random() * alphabet.length)]
      }
      return string
    }


    Берите nanoid и не мучайтесь
    Ответ написан
    Комментировать
  • Что делает оператор "||" при присвоении?

    @askhat
    Эквивалентно
    var URL
    if (window.URL) {
      URL = window.URL
    } else {
      URL = window.webkitURL
    }
    Ответ написан
    Комментировать
  • Как получить элемент из JSON JavaScript?

    @askhat
    const tmp = '{ "qwerty": "1234567890" }';
    console.log(JSON.parse(tmp).qwerty);        // OK --- 1234567890
    
    // Потому что синтаксис другой
    var id = 'qwerty';
    console.log(JSON.parse(tmp)[id]);        // OK --- 1234567890
    Ответ написан
    Комментировать
  • Как вывести разные значения value при смене option?

    @askhat
    You might not need jQuery
    document.querySelector('.tovar1 select').onchange = e => console.log(e.target.value)
    Ответ написан
    Комментировать
  • Как удалить пробелы из input?

    @askhat
    const stringWithNoWhitespace = string.replace(/\s/g, '')
    Ответ написан
  • Можно ли переделать скрипт плавного скролла?

    @askhat
    <button class="slowly" data-target="some_id">Take me there but slowly</button>


    $(".slowly").on("click", function (event) {
          /*Отменяем стандартную обработку нажатия по ссылке.*/
          event.preventDefault();
          /*Забираем идентификатор блока с атрибута href.*/
          var id = $(this).attr('href') || $(this).attr('data-target');
          /*Узнаём высоту от начала страницы до блока, на который ссылается якорь.*/
          var top = $(id).offset().top;
          /*Анимируем переход на расстояние - top за 1000ms.*/
          $('body,html').animate({scrollTop: top}, 1200);
    Ответ написан
    1 комментарий
  • Как реализовать frontend часть отправки формы на Vue.js?

    @askhat
    <template>
      <form>
        <p v-if='errorMessage'>{{ errorMessage }}</p>
        <input type='text' v-model='username'/>
        <input type='password' v-model='password'/>
        <button @click='send()'>Log in</button>
      </form>
    </template>
    
    <script>
    import someHttpClient from 'someHttpClient'
    
    export default {
      data: {
        return {
          username: '',
          password: '',
          errorMessage: ''
        }
      },
      methods: {
        send () {
          var username, password, errorMessage = this
          if (username && password) {
            errorMessage = ''
            someHttpClient.sendAndMaybeCipher({ username, password })
          } else {
            errorMessage = 'Form not filled properly'
          }
        }
      }
    }
    </script>


    Примеры запроса:
    Ответ написан
  • Вывод данных в определенный период времени?

    @askhat
    var date = new Date()
    if (date.getDate() === 25 && date.getMonth() === 11) {
      showMessage()
    }
    Ответ написан
    1 комментарий
  • Какое значение из input type=file передавать на сервер?

    @askhat
    File это специальный тип Blob ~ MDN

    Вы можете использовать объект File в качестве аргумента метода #sendXMLHttpRequest, чтобы отправить его в теле POST запроса. Например:
    function eventHandler (event) {
      const file = event.files[0];
      const xhr = new XMLHttpRequest();
      xhr.open('POST', '/someroute', true)
      xhr.onreadystatechange = function () {
        if (xhr.status === 200) {
          console.log(xhr.reponseText);
        }
      }
    }
    xhr.send(file);
    Ответ написан
    Комментировать
  • Фильтрация дерева в ExtJs?

    @askhat
    {
        xtype: 'triggerfield',
        listeners: {
            change: function(newVal, oldVal, field) {
                console.log('new value', newVal);
                console.log('old value', oldVal);
                console.log('field', field);
            } 
        }
    }
    Ответ написан
    8 комментариев
  • Чем отличается ajax-запрос post от get?

    @askhat
    Чем POST отличается от GET

    Семантика HTTP методов на высоком уровне подразумевает операции создания и получения сущности(-стей) методами POST и GET соответственно. На прикладном уровне это означает одно: у метода GET отсутствует `body`, в то время как оно присутствует в POST. Для передачи данных (payload), для создания сущности, например для сохранения новой строчки в БД.

    Синтаксис XHR
    Классическим способом создания такого запроса в браузере станет api `XMLHttpRequest`.

    const data = {whatever: 'payload'};
    // Создадим объект xhr для обработки запроса
    const xhr = new XMLHttpRequest();
    // Открываем запрос
    // @param String - типзапроса
    // @param String - путь до слушателя
    // @param Boolean - true async / false sync
    // Запрос ещё не отправлен
    xhr.open('POST', '/someroute', true)
    // Указываем что это AJAX запрос
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    // Указываем что это JSON payload
    xhr.setRequestHeader('Content-Type', 'application/json');
    // Коллбек запускается при смене состояния xhr
    xhr.onreadystatechange = function () {
      if (xhr.status === 200) {
        console.log(xhr.reponseText);
      }
    };
    // Отправляем запрос
    xhr.send(JSON.stringify(data));


    fetch API

    Вот многих браузерах уже имплементирован fetch API. Скорее всего это станет стандартом, однако используйте на свой страх и риск.

    const data = {whatever: 'payload'};
    // Начнём с заголовков
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');
    // Функция должна вернуть объект Promise
    return fetch('/someroute', {
      method: 'POST',
      headers: headers,
      body: JSON.stringify(data);
    }).then(raw => raw.json()).then(response => {
      console.log(response);
    });


    PS Обратите внимание, в примере отсутствует обработка ошибок, что приведёт к `warning: UnhandledPromiseRejectionWarning: Unhandled promise rejection`
    Ответ написан
    Комментировать
  • Как подключить глобально плагин jquery на vue.js?

    @askhat
    Если не через NPM, то через CDN. Открывайте свой index.html и добавляйте ссылки.

    Но скорее всего вас интересует как заставить это работать. Тут два варианта:

    1. Через хук:
    export default {
      // mounted неплохой вариант, если document должен быть ready
      mounted () {
        const $ = window.$
        $('.main').onepage_scroll()
      }
    }


    2. Или через кастомную директиву:
    export default {
      directives: {
        // Произвольное имя директивы
        onePageScroll: {
          // На этом хуке компонент со всеми дочерними компонентами готов
          componentUpdated (el) {
            const $ = window.$
            // Елемент не нужно «селектить» по классу/ИД т.к. он передан в аргументы директивы
            $(el).onepage_scroll()
          }
        }
      }
    }

    <div>
      <section v-one-page-scroll />
    </div>


    Не уверен, что именно приведённые хуки буду работать хорошо/вообще—попробуйте разные варианты.
    Ответ написан
    Комментировать