Задать вопрос
  • Как правильно настроить слайдер и поп-ап Vuetify?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Не могу закрыть поп-ап

    dialog: [],

    dialog[index]= false

    Кто-то невнимательно читал документацию.

    При нажатии на кнопку, при выборе 3 изображения на превью открывается всегда первое.

    Не всегда, а при первом открытии каждого диалога.

    Кстати, непонятно - а зачем вам три диалоговых окна? Сделайте одно:

    data: () => ({
      slide: null,
      dialog: false,
      ...
    }),
    methods: {
      openDialog(slideIndex) {
        this.slide = slideIndex;
        this.dialog = true;
      },
      ...
    },

    v-row
      v-col(v-for="(n, i) in pictures")
        v-item
          v-img(height="100", width="100", :src="n", @click="openDialog(i)")
      v-col(hidden="")
        v-dialog(v-model="dialog")
          v-carousel(v-model="slide")
            v-carousel-item(v-for="n in pictures")
              v-img(:src="n")
          v-btn(@click="dialog = false") close dialog
    Ответ написан
    1 комментарий
  • Почему не рендерится компонент?

    0xD34F
    @0xD34F Куратор тега React
    В MainWindow должно быть так:

    <div className="mainWindow">
      {this.props.children}
    </div>

    Компонент Field - откуда вы взяли, что внутрь input можно что-то помещать? Это непарный тэг. Закрывающий тэг вырезать, добавить слеш в конец открывающего. Что дальше - вам виднее, всё зависит от того, как вы предполагаете использовать props.data. Обернуть всё в label, или сделать data значением input'а.
    Ответ написан
  • Как передать props в компонент во Vue 3 через роутинг?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сначала пара слов о том, как правильно:

    Роутинг для передачи данных в этой ситуации использовать не надо. Подключаете vuex, кладёте массив в хранилище, компонент home никаких параметров не принимает, просто достаёт из хранилища нужные данные и передаёт их в компонент posts:

    <posts :posts="$store.state.posts" />

    Как видите, всё элементарно.

    Передача же "через роутинг" обернётся говнокодерством:

    • Можно сделать маршрут именованным и передавать через params:

      <router-link :to="{ name: 'home', params: { posts } }">home</router-link>

      this.$router.push({
        name: 'home',
        params: {
          posts: this.posts,
        },
      });

      Сразу же очевиден первый недостаток такого способа: в скольких местах осуществляется переход на роут home, столько раз придётся и передавать туда явным образом массив posts, указывая его в params каждого router-link или вызова $router.push. При этом, если переход осуществляется не из корневого компонента, то, чтобы дотянуться до posts, придётся ещё и $root использовать. В случае же, когда пользователь решит осуществить переход посредством адресной строки браузера, то ничего передать не получится.

      Ещё один недостаток станет очевидным после перехода - оказывается, элементы posts превратились в строки. Роутер приводит к строкам значения свойств params (или, если свойство является массивом, к строкам будут приведены его элементы). Так что для корректной передачи ещё придётся и в json данные конвертировать, а в компоненте home этот json парсить - говнокод, как и обещал.

    • Можно прицепить данные к router-view, тогда они будут переданы как параметры в компонент текущего маршрута: <router-view :posts="post" />.

      Тут тоже не всё пройдёт гладко - так передача параметров будет осуществляться в компоненты всех маршрутов, и там, где переданные параметры не описаны, они будут сочтены атрибутами и прицеплены к корневому элементу (если он один; когда несколько - надо явным образом указывать, куда добавлять $attrs). Чтобы передавать что надо только куда надо, можно оформить параметры, передаваемые в router-view, как вычисляемое свойство, значение которого будет зависеть от текущего маршрута:

      computed: {
        routeParams() {
          return что-то, в зависимости от this.$route;
        },
      },

      <router-view v-bind="routeParams" />

    Ответ написан
  • Как закрывать всплывающее окно в react?

    0xD34F
    @0xD34F Куратор тега React
    Следить за кликами за пределами корневого узла:

    function Modal(props) {
      const root = useRef();
    
      useEffect(() => {
        const onClick = e => root.current.contains(e.target) || закрытьОкно();
        document.addEventListener('click', onClick);
        return () => document.removeEventListener('click', onClick);
      }, []);
    
      return (
        <div ref={root}>
          ...
        </div>
      );
    }

    Или сделать так, чтобы корневой узел перекрывал всю страницу, и отслеживать клики по нему:

    function Modal(props) {
      return (
        <div
          className="modal-overlay"
          onClick={e => (e.currentTarget === e.target) && закрытьОкно()}
        >
          ...
        </div>
      );
    }

    .modal-overlay {
      position: absolute;
      left: 0;
      top: 0;
      width: 100vw;
      height: 100vh;
      background: rgba(0, 0, 0, 0.5);
    }
    Ответ написан
    1 комментарий
  • Как по нажатой кнопке идентифицировать строку в таблице?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Повесить на таблицу обработчик клика; внутри проверять, кто был нажат - если кнопка, получить ближайшего предка, который является строкой таблицы:

    document.querySelector('table').addEventListener('click', ({ target: t }) => {
      if (t.classList.contains('save_order')) {
        const tr = t.closest('tr');
        console.log(tr);
      }
    
      // или
    
      if (t.matches('.save_order')) {
        let tr = t;
        while ((tr = tr.parentNode).tagName !== 'TR') ;
        console.log(tr);
      }
    });
    Ответ написан
    Комментировать
  • Как удалить последний элемент массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Удаляем один элемент:

    arr.pop();
    
    // или
    
    arr.length -= !!arr.length;
    
    // или
    
    arr.splice(-1);

    Удаляем несколько (const count = сколько надо удалить;):

    for (let i = count; --i >= 0 && arr.length; arr.pop()) ;
    
    // или
    
    arr.length -= Math.max(0, Math.min(arr.length, count));
    
    // или
    
    count > 0 && arr.splice(-count);
    Ответ написан
    Комментировать
  • Как вывести данные из двух массивов?

    0xD34F
    @0xD34F
    echo implode('', array_map(function($author, $book) {
      return '<p>Книга '.$book['nameBook'].', ее написал '.$author['fio'].', '.$author['email'].'</p>';
    }, $arr['authors'], $arr['books']));
    Ответ написан
    3 комментария
  • Как обрабатывать событие на всех элементах, имеющих определённый класс?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Делегирование, назначаем обработчик события один раз для всех:

    document.addEventListener('input', ({ target: t }) => {
      if (t.classList.contains('rating__value')) {
        const value = +t.value;
    
        t.closest('.item-rating').querySelector('.rating__dynamic').innerHTML = Array
          .from({ length: 5 }, (n, i) => `<span class="char">${'☆★'[+(value > i)]}</span>`)
          .join('');
      }
    });
    
    document.querySelectorAll('.rating__value').forEach(n => {
      n.dispatchEvent(new Event('input', { bubbles: true }));
    });

    Или, каждому элементу индивидуально:

    for (const n of document.getElementsByClassName('rating__value')) {
      n.previousElementSibling.innerHTML = '<span class="char"></span>'.repeat(5);
      n.addEventListener('input', onRatingInput);
      onRatingInput.call(n);
    }
    
    function onRatingInput() {
      const value = this.value | 0;
      const stars = this.previousElementSibling.children;
    
      for (let i = 0; i < stars.length; i++) {
        stars[i].innerText = value > i ? '★' : '☆';
      }
    }
    Ответ написан
  • Как сделать добавление tr в таблицу по условию?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Такие есть варианты:

    1. Сделать отдельный tbody для каждой пары строк. Переносите tbody из компонента таблицы в компонент строки - будет там корневым элементом:

      <tbody>
        <tr>... </tr>
        <tr v-if="...">...</tr>
      </tbody>

      Пример.

    2. Сделать компонент строки функциональным - там может быть несколько корневых узлов. Пример.
    3. Отказаться от использования компонента строки, рендерить tr сразу в компоненте таблицы:

      <tbody>
        <template v-for="...">
          <tr>... </tr>
          <tr v-if="...">...</tr>
        </template>
      </body>

      Пример.

    4. Переехать на Vue 3 - там можно сделать компонент с несколькими корневыми узлами. Пример.
    5. Попробовать использовать костыль. Здесь примера не будет - к этой штуке не прикасался и не собираюсь.
    Ответ написан
    Комментировать
  • Как создать динамический шаблон при компонентном подходе без создания и дальнейшего перебора массива в массиве в еще одном массиве?

    0xD34F
    @0xD34F Куратор тега Vue.js
    А откуда там взяться массиву в массиве и т.д.? Нужен массив объектов, которые описывают поля формы, а также объект с данными формы (это то, что сейчас у вас представлено отдельными свойствами). Всё:

    data: () => ({
      formData: {},
      formMeta: [
        { name: 'phone', title: 'Телефон', type: 'text', placeholder: 'Телефон' },
        { name: 'email', title: 'E-mail', type: 'text', placeholder: 'E-mail' },
        { name: 'address', title: 'Адрес', type: 'text', placeholder: 'Адрес' },
        ...
      ],
    }),

    this.$emit('save-contact', this.formData);

    <div v-for="n in formMeta">
      <span class="form__other-title">{{ n.title }}</span>
      <div class="form__other-data">
        <input
          v-model="formData[n.name]"
          :type="n.type"
          :placeholder="n.placeholder"
        >
      </div>
    </div>
    Ответ написан
  • Как создать табы на vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    работать с dom напрямую плохая практика

    Не всегда. Зависит от задачи.

    Пусть компонент табов принимает в качестве параметров массив значений, описывающих табы и значение, обозначающее активный таб:

    props: [ 'items', 'value' ],

    В данные компонента положим стили для элемента, изображающего подчёркивание активного таба:

    data: () => ({
      sliderStyles: null,
    }),

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

    <ul class="tabs">
      <li
        v-for="n in items"
        :key="n.value"
        @click="$emit('input', n.value)"
        class="tabs-item"
      >{{ n.text }}</li>
    </ul>
    <div
      class="tabs-slider"
      :style="sliderStyles"
    ></div>

    Элементу подчёркивания (.tabs-slider) зададим абсолютное позиционирование и transition.

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

    mounted() {
      this.$watch(
        'value',
        value => {
          const index = this.items.findIndex(n => n.value === value);
          const el = this.$el.querySelectorAll('.tabs-item')[index];
          this.sliderStyles = el
            ? {
                left: `${el.offsetLeft}px`,
                width: `${el.offsetWidth}px`,
              }
            : null;
        },
        {
          immediate: true,
        }
      );
    },

    https://jsfiddle.net/vsr5tLue/
    Ответ написан
    Комментировать
  • Как переключать активный класс у итема?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const listTag = 'ul';
    const listClass = 'list';
    const itemTag = 'li';
    const itemClass = 'item';
    const activeClass = 'active';

    Вариант раз - перебираем все элементы списка, каждому переключаем класс в зависимости от его равенства кликнутому:

    const list = document.createElement(listTag);
    const items = arr.map(function(n) {
      const item = document.createElement(itemTag);
      item.textContent = n.text;
      item.classList.add(itemClass);
      item.addEventListener('click', this);
      return item;
    }, function() {
      list.style.setProperty('background-image', `url(${arr[items.indexOf(this)].url})`);
      items.forEach(n => n.classList.toggle(activeClass, n === this));
    });
    
    list.classList.add(listClass);
    list.append(...items);
    document.body.append(list);
    
    items[0].click();

    Вариант два - ищем внутри списка элемент с классом, удаляем у него класс, добавляем класс кликнутому элементу:

    document.body.insertAdjacentHTML('beforeend', `
      <${listTag} class="${listClass}">${arr.map(({ url, text }) => `
        <${itemTag} class="${itemClass}" data-url="${url}">${text}</${itemTag}>`).join``}
      </${listTag}>
    `);
    
    const list = document.body.lastElementChild;
    
    list.addEventListener('click', ({ target: t }) => {
      if (t = t.closest(`${itemTag}.${itemClass}`)) {
        list.style.backgroundImage = `url(${t.dataset.url})`;
        list.querySelector(`.${activeClass}`)?.classList.remove(activeClass);
        t.classList.add(activeClass);
      }
    });
    
    list.children[0].dispatchEvent(new Event('click', { bubbles: true }));
    Ответ написан
    Комментировать
  • Как заменить разделитель внутри строки на PHP?

    0xD34F
    @0xD34F
    $newStr = preg_replace('~(?<=^|,)~', '.n', $str);
    
    // или
    
    $newStr = preg_replace('~\d+~', '.n$0', $str);
    
    // или
    
    $newStr = implode(',', array_map(fn($n) => ".n$n", explode(',', $str)));
    Ответ написан
    Комментировать
  • Как правильно отсортировать свойства данные по дате и времени?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const sorted = (arr, key) => arr
      .map(n => [ key(n), n ])
      .sort(([a], [b]) => a < b ? -1 : +(a > b))
      .map(n => n[1]);

    const sortedArr = sorted(
      arr,
      n => new Date(n.date.replace(/(\d+)\.(\d+)\.(\d+)/, '$3-$2-$1'))
    );
    
    // или
    
    const sortedArr = sorted(
      arr,
      n => n.date.replace(/[^T]+/, m => m.split('.').reverse().join(''))
    );
    Ответ написан
    2 комментария
  • Как разделить элементы списка?

    0xD34F
    @0xD34F
    arr[0].split(' ') + arr[3:]
    Ответ написан
    Комментировать
  • Как найти минимальную сумму после уникализации элементов массива путём инкрементирования дубликатов?

    0xD34F
    @0xD34F
    Отсортировать массив, при суммировании в качестве слагаемого брать текущий элемент массива или предыдущее слагаемое + 1, в зависимости от того, кто окажется больше:

    const getMinimumUniqueSum = arr => [...arr]
      .sort((a, b) => a - b)
      .reduce((acc, n) => (acc[1] += acc[0] = Math.max(acc[0] + 1, n), acc), [ -Infinity, 0 ])
      .pop();
    Ответ написан
    1 комментарий
  • Как изменять вложенные комментарии (объекты) в vuex store?

    0xD34F
    @0xD34F
    Передавайте в мутацию вместо id сам объект комментария - тогда ничего искать будет не надо.

    Или сделайте рекурсивную функцию поиска, что-то вроде

    const find = (arr, id) =>
      (Array.isArray(arr) ? arr : []).reduce((found, n) =>
        found || (n.id === id ? n : find(n.replies, id))
      , null);
    Ответ написан
    3 комментария
  • Как переделать код из jQuery в JavaScript?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Год назад фрилансер сделал код

    Сама в JavaScript и jQuery не сильна.

    По-моему, ответ очевиден - наймите ещё одного фрилансера.
    Ответ написан
    Комментировать