Задать вопрос
  • Как последовательно анимировать элементы внутри transition-group?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Добавим в компонент свойство, указывающее, сколько элементов надо отображать:

    data: () => ({
      numShow: 0,
      ...

    С его помощью будем получать массив отображаемых элементов:

    computed: {
      itemsToShow() {
        return this.items.slice(0, this.numShow);
      },
      ...

    Создадим методы для показа следующего или скрытия предыдущего элемента - для этого достаточно делать +/- 1 количеству отображаемых элементов:

    methods: {
      showNext() {
        this.numShow = Math.min(this.items.length, this.numShow + 1);
      },
      hidePrev() {
        this.numShow = Math.max(0, this.numShow - 1);
      },
      ...

    Повесим этим методы в качестве обработчиков событий завершения показа и скрытия элемента:

    <transition-group
      @after-enter="showNext"
      @after-leave="hidePrev"
      ...
    >
      <div 
        v-for="(n, i) in itemsToShow"
        :key="n.id"
        ...
      >
      ...

    Запуск процесса анимации - только из крайних положений, когда ничего не отображается или отображается всё:

    methods: {
      run() {
        this.numShow += ({
          0: 1,
          [this.items.length]: -1,
        })[this.numShow] || 0;
      },
      ...

    https://jsfiddle.net/6Ljzpeu2/

    А вообще, в документации есть пример на эту тему.
    Ответ написан
    1 комментарий
  • Почему выходит ошибка Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`. in Route?

    0xD34F
    @0xD34F Куратор тега React
    Почему - так написано же. Передаёте в Route не то, что надо, Auth должен быть функцией, а не объектом.

    Почему Auth объект - непонятно, про свой код вы явно наврали, экспортируется не какой-то там объект, а... ничего. Вообще никакого экспорта не вижу. А должен быть:

    export default class UserForm ...

    И вызов ReactDOM.render в Auth не нужен.
    Ответ написан
  • Как вывести значение из axios в рендер?

    0xD34F
    @0xD34F Куратор тега React
    Можно завести свойство в стейте, содержащее сообщение об ошибке, если имеет не falsy значение - выводить его, как-то так (вместо вашего запроса тут просто setTimeout и генерация случайных данных, но, думаю принцип понятен).
    Ответ написан
    Комментировать
  • Как можно на VUE реализовать простенький фильтр?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Добавить два свойства - массив, описывающий типы, и тип, данные которого надо отобразить:

    data: () => ({
      types: [
        { id: null, name: 'Все' },
        { id: ..., name: '...' },
        { id: ..., name: '...' },
        ...
      ],
      active: null,
      ...

    Дать пользователю возможность выбирать тип отображаемых данных:

    <button v-for="n in types" @click="active = n.id">{{ n.name }}</button>
    
    <!-- или -->
    
    <select v-model="active">
      <option v-for="n in types" :value="n.id">{{ n.name }}</option>
    </select>
    
    <!-- или -->
    
    <label v-for="n in types">
      <input type="radio" name="type" :value="n.id" v-model="active">
      {{ n.name }}
    </label>

    Сделать вычисляемое свойство, которое будет представлять отфильтрованные данные:

    computed: {
      filteredItems() {
        const { items, active } = this;
        return active ? items.filter(n => n.type === active) : items;
      },
      ...

    Показать результат фильтрации:

    <tr v-for="(n, i) in filteredItems">
      ...

    https://jsfiddle.net/jhekutv3/
    Ответ написан
    Комментировать
  • В Postgresql записать в дефолт пустое значение, но не null?

    0xD34F
    @0xD34F
    ALTER TABLE "table_name" ALTER COLUMN "column_name" SET DEFAULT '';
    Ответ написан
    Комментировать
  • Как найти в массиве минимальное положительное число?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const positives = arr.filter(n => n > 0);
    const minPositive = positives.length
      ? Math.min(...positives)
      : null;

    или

    const minPositive = arr.reduce((min, n) => (n > 0 && (n < min || min === null)) ? n : min, null);
    Ответ написан
    Комментировать
  • SVG фильтр или маска при наведении?

    0xD34F
    @0xD34F Куратор тега CSS
    Можно использовать mix-blend-mode: difference;. Типа так.

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

    0xD34F
    @0xD34F Куратор тега React
    В смысле - вам надо не давать пользователю переходить к следующему вопросу при отсутствие ответа?

    Можно сделать массив полученных от пользователя ответов, и при выборе какого-либо пункта обновлять его по индексу текущего вопроса, кнопке перехода к следующему вопросу назначать disabled в зависимости от количества ответов. Типа так.
    Ответ написан
  • Как удалить предыдущий класс?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Можно удалять все возможные классы:

    const classes = $buttons.get().map(n => n.dataset.set);
    
    $buttons.click(function() {
      $('.current').removeClass('current');
      $(this).addClass('current');
    
      $blocks.removeClass(classes.join(' ')).addClass(this.dataset.set);
    });

    Или запоминать последний добавленный:

    let currentClass = null;
    
    $buttons.click(function() {
      $('.current').removeClass('current');
      $(this).addClass('current');
    
      const newClass = this.dataset.set;
      $blocks.removeClass(currentClass).addClass(newClass);
      currentClass = newClass;
    });
    Ответ написан
    2 комментария
  • Как вставить div перед последним абзацем?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кого и куда надо перенести:

    const parent = document.querySelector('здесь селектор элемента с абзацами');
    const el = document.querySelector('а здесь - элемента, который хотите перенести');

    Как получить последний вложенный элемент:

    const last = parent.lastElementChild;
    
    // или
    
    const last = parent.querySelector(':scope > :last-child');
    
    // или
    
    const last = parent.children[parent.children.length - 1];
    
    // или
    
    const [ last ] = Array.prototype.slice.call(parent.children, -1);

    Переносим:

    last.before(el);
    
    // или
    
    last.insertAdjacentElement('beforebegin', el);
    
    // или
    
    last.replaceWith(el, last);
    
    // или
    
    parent.insertBefore(el, last);
    Ответ написан
    Комментировать
  • Цикл создает лишнюю пустую строку?

    0xD34F
    @0xD34F
    if ($days_in_this_week < 8) {

    И как называется этот восьмой день? Я, честно говоря, не понял, зачем тут лишняя единица. В любом случае, проверять надо не верхнюю границу (всё равно выйти за неё не позволит условие продолжения цикла), а нижнюю - что в последней строке уже что-то есть, что она не пустая:

    if ($days_in_this_week > 1) {

    Но вообще, пустая строка в конце - это вовсе не косяк. Сколько строк всего может быть? - от четырёх (не високосный февраль, начинающийся в понедельник) до шести (месяц из 30 дней начинается в воскресенье, из 31 дня в воскресенье или субботу). Как-то не единообразно. Пусть всегда будет шесть строк, чтобы размер календаря не зависел от месяца. Так что отступаем от начала месяца назад до ближайшего понедельника, затем выводим 42 дня (шесть недель):

    function drawCalendar($year, $month) {
      $date = DateTime::createFromFormat('Y-m-d', "$year-$month-1");
      $day = DateInterval::createFromDateString('1 day');
      $weekdays = [ 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс' ];
    
      do {
        $date->sub($day);
      } while ($date->format('w') !== '1');
    
      $days = [];
      for ($i = 0; $i < 42; $i++, $date->add($day)) {
        $m = intval($date->format('m'));
        $days[] = $m === $month ? intval($date->format('d')) : '&nbsp;';
      }
    
      return "
    <table cellpadding=\"5\" cellspacing=\"5\" border=\"1\">
      <thead>
        <tr class=\"b-calendar__row\">".implode('', array_map(function($n) { return "
          <th class=\"b-calendar__head\">$n</th>"; }, $weekdays))."
        </tr>
      </thead>
      <tbody>".implode('', array_map(function($week) { return "
        <tr class=\"b-calendar__row\">".implode('', array_map(function($n, $i) { return "
          <td class=\"b-calendar__day ".($i > 4 ? 'b-calendar__weekend' : '')."\">
            $n
          </td>"; }, $week, array_keys($week)))."
        </tr>"; }, array_chunk($days, 7)))."
      </tbody>
    </table>";
    }
    
    
    echo drawCalendar(2018, 1);
    Ответ написан
    Комментировать
  • Как сделать поля привязанные к этому блоку?

    0xD34F
    @0xD34F Куратор тега React
    Ну, input'ы у вас уже есть, осталось только добавить обработчик onChange, в котором будет происходить обновление данных. И конечно, чтобы можно было управлять видимостью инпутов независимо, свойство, отвечающее за их отображение, должно быть не одно на все блоки, а у каждого своё:

    class App extends React.Component {
      state = {
        data: [
          '#088A85', '#0B2F3A', '#0B0B3B', '#2A0A29', '#B4045F',
          '#FA58F4', '#A9BCF5', '#58FA82', '#A9F5F2', '#CED8F6',
        ].map((n, i) => ({
          id: i + 1,
          color: n,
          title: `block #${i}`,
          opened: false,
        })),
      }
    
      updateItem(index, key, val) {
        const data = [...this.state.data];
        data[index][key] = val;
        this.setState({ data });
      }
    
      render() {
        return (
          <div>{this.state.data.map(({ id, color, title, opened }, i) => (
            <div key={id}>
              <div
                className="square"
                style={{ backgroundColor: color }}
                onClick={() => this.updateItem(i, 'opened', !opened)}
              >
                <p>{title}</p>
              </div>
              {opened &&
              <div>
                <input
                  value={color}
                  onChange={e => this.updateItem(i, 'color', e.target.value)}
                />
                <input
                  value={title}
                  onChange={e => this.updateItem(i, 'title', e.target.value)}
                />
              </div>}
            </div>))}
          </div>
        )
      }
    }

    .square {
      width: 100px;
      height: 100px;
    }
    Ответ написан
    Комментировать
  • Не работает добавление количества товара на сайте, в чем проблема?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Оба обработчика назначены одним и тем же элементам - .services_minus. То есть, при клике на плюс не происходит вообще ничего, а минус - количество будет уменьшаться, и сразу же увеличиваться обратно.

    Относительное расположение кнопок и элемента с количеством совсем не то, что вам кажется. Вместо того, чтобы хватать следующий элемент после кликнутой кнопки, надо от кнопки подняться до общего её и количества предка, внутри которого уже искать количество. Т.е., .next('.services_nomer') следует заменить на

    .closest('.services_button_block').find('.services_nomer')

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

    $('.services_minus').click(function() {
      $(this)
        .closest('.services_button_block')
        .find('.services_nomer')
        .text((i, text) => Math.max(0, text - 1));
    });
    
    $('.services_plus').click(function() {
      $(this)
        .closest('.services_button_block')
        .find('.services_nomer')
        .text((i, text) => +text + 1);
    });
    Ответ написан
    9 комментариев
  • Как вывести все элементы списка (в том числе вложенные)?

    0xD34F
    @0xD34F Куратор тега JavaScript
    почему после возвращения из рекурсивного вызова i=3 а не 2?

    Не выдумывайте, там 2. Хотя должно быть 1.

    То, что функция работает не так, как вы ожидаете - это потому что переменная i является глобальной. А то, что вообще работает - потому что строгий режим не включался. Погуглите, что происходит при присваивании значения необъявленной переменной.

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

    if (numbers[i].length) {

    Условие рекурсивного вызова кривое - что, если какой-то из вложенных массивов окажется пустым? Он тогда будет рассматриваться как значение, которое должно быть помещено в массив с результатами.

    Исправляем (и переписываем).
    function flat(arr) {
      const result = [];
    
      for (const n of arr) {
        if (n instanceof Array) {
          result.push(...flat(n));
        } else {
          result.push(n);
        }
      }
    
      return result;
    }
    
    // или
    
    const flat = arr =>
      Array.prototype.concat.apply(
        [],
        arr.map(n => Array.isArray(n) ? flat(n) : n)
      );
    Ответ написан
    Комментировать
  • Как округлить время Moment.js с точностью до 5 минут?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const interval = 5 * 60 * 1000 // 5 минут, ага
    const x = moment(Math.ceil(moment() / interval) * interval).format('HH:mm:ss')
    Ответ написан
    1 комментарий
  • Зачем тут нужен apply()?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Почему я не могу сделать просто func(args) ?

    Потому что args - это массив аргументов, а вы должны передавать их по отдельности.

    Зачем нужно подставлять контекст?

    Не нужно. Можете делать так: func(...args).
    Ответ написан
    3 комментария
  • Как добавить условие, если input поле уже заполнено?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Можно затриггерить событие change после установки обработчика, вызвав соответствующий метод без параметров:

    $elems.change(function() {
      ...
    }).change();

    Или, если такой способ вам не подходит (например, ранее устанавливались другие обработчики change, и вы не хотите, чтобы они сработали), можно применить each, передав ему обработчик:

    function onChange() {
      ...
    }
    
    $elems.change(onChange).each(onChange);
    Ответ написан
    Комментировать
  • Как написать приложение перестановки набора карточек?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Ну типа вот, дальше допиливайте сами:

    class Game extends React.Component {
      state = {
        panesCurrent: [],
        panesDefault: [ 1, 1, 1, 0, -1, -1, -1 ],
        panesWin: [ -1, -1, -1, 0, 1, 1, 1 ],
      }
    
      componentDidMount() {
        this.reset();
      }
    
      componentDidUpdate() {
        if (this.state.panesCurrent.every((n, i) => n === this.state.panesWin[i])) {
          setTimeout(alert, 25, 'WIN');
        }
      }
    
      onClick(index) {
        const clicked = this.state.panesCurrent[index];
        if (clicked === 0) {
          return;
        }
    
        for (let i = 1; i <= 2; i++) {
          const t = index + clicked * i;
          if (this.state.panesCurrent[t] === 0) {
            const panes = [...this.state.panesCurrent];
            [ panes[index], panes[t] ] = [ panes[t], panes[index] ];
            this.setState({ panesCurrent: panes });
            break;
          }
        }
      }
    
      reset = () => {
        this.setState(({ panesDefault }) => ({
          panesCurrent: [...panesDefault],
        }));
      }
    
      render() {
        return (
          <div>
            <button onClick={this.reset}>reset</button>
            <div className="game">
              {this.state.panesCurrent.map((n, i) => (
                <div
                  className={'pane ' + [ 'left', '', 'right' ][n + 1]}
                  onClick={() => this.onClick(i)}
                ></div>
              ))}
            </div>
          </div>
        )
      }
    }

    .game {
      font-size: 5px;
    }
    
    .pane {
      display: inline-block;
      width: 10em;
      height: 10em;
      margin: 1em;
    }
    
    .pane.right::after,
    .pane.left::after {
      position: relative;
      display: inline-flex;
      justify-content: center;
      align-items: center;
      width: 100%;
      height: 100%;
      font-family: monospace;
      font-size: 4em;
    }
    .pane.right::after {
      content: "-->";
      color: red;
      border: 2px solid red;
    }
    .pane.left::after {
      content: "<--";
      color: lime;
      border: 2px solid lime;
    }
    Ответ написан
    2 комментария