Ответы пользователя по тегу Vue.js
  • Как вывести общую сумму в корзине?

    0xD34F
    @0xD34F Куратор тега Vue.js
    item.isAdded = true

    Это как, одни и те же объекты используются и в списке товаров, и в корзине? Можете начинать думать, как будете переделывать, чтобы такой ерунды не было. Ну а пока попробуем заставить ваш говнокод вести себя должным образом:

    const quantity = ref(1)

    Что, закрыли корзину и потеряли данные о количестве? Пусть количество будет свойством элемента массива, представляющего корзину, соответственно, приходит сверху, и туда же отправляется новое:

    const quantity = defineModel('quantity');

    В родителе ловим это новое количество и дёргаем метод обновления:

    <CartItem
      v-for="n in cart"
      v-bind="n"
      :key="n.id"
      @update:quantity="updateQuantity(n, $event)"
      @remove="removeFromCart(n)"
    />

    Откуда этот метод возьмётся? Оттуда же, откуда и методы добавления (этот вам придётся поправить самостоятельно, при добавлении в корзину надо задавать количество по умолчанию, типа единица) и удаления, делаем по аналогии:

    const updateQuantity = (item, quantity) => item.quantity = quantity;

    Ну и наконец, исправленный расчёт суммы, цену надо умножать на количество:

    const totalPrice = computed(() => cart.value.reduce((acc, n) => acc + n.price * n.quantity, 0));
    Ответ написан
    Комментировать
  • Vue-router не изменяет url страницы при нажатии RouterLink. Содержимое меняется. В чем может быть проблема?

    0xD34F
    @0xD34F Куратор тега Vue.js
    history: createMemoryHistory(),

    Vue-router не изменяет url страницы

    А должен? Лично я слышал, что нет:

    The memory history mode doesn't assume a browser environment and therefore doesn't interact with the URL
    Ответ написан
    Комментировать
  • Как создать фильтрацию через select на vue 3 с composition api?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Вот так:

    Компонент FilterBlock
    const status = defineModel('status');
    const statuses = [ 'all', 'alive', 'dead', 'unknown' ];

    <select v-model="status">
      <option v-for="n in statuses">{{ n }}</option>
    </select>

    Компонент СardList
    defineProps({
      data: {
        type: Array,
        default: () => [],
      },
    });

    <div v-for="n in data">
      <span :class="[ 'status', n.status ]"></span>
      ...
    </div>

    .status {
      border-radius: 50%;
      width: 30px;
      height: 30px;
    
      &.alive { background: green; }
      &.dead { background: red; }
      &.unknown { background: orange; }
    }

    Компонент App
    const data = ref([ ... ]);
    const status = ref('all');
    const filteredData = computed(() => status.value === 'all'
      ? data.value
      : data.value.filter(n => n.status === status.value)
    );

    <FilterBlock v-model:status="status" />
    <CardList :data="filteredData" />
    Ответ написан
    Комментировать
  • Почему не работает v-model для компонента?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Версия vue какая?

    Если 3, то всё ясно:

    BREAKING: When used on custom components, v-model prop and event default names are changed:
    • prop: value -> modelValue;
    • event: input -> update:modelValue;

    Если 2 - явных косяков не видно, воспроизводите проблему в песочнице, ссылку сюда.
    Ответ написан
    1 комментарий
  • Как переместить колонку с checkbox вправо, в компоненте QTable, Quasar?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Что-то не видать в документации соответствующей настройки (UPD. Да её и нет, глянул в исходниках, как происходит добавление колонки с чекбоксами - unshift, и ничего больше). Давайте закостылим - добавляем колонку, которая будет дублировать данный функционал, а оригинальную спрячем:

    const columns = [
      ...
      { name: 'selection' },
    ];

    .xxx tr > :first-child {
      display: none;
    }

    <q-table
      ...
      table-class="xxx"
    >
      <template #header-cell-selection="props">
        <q-th :props="props">
          <q-checkbox v-model="props.selected" />
        </q-th>
      </template>
    
      <template #body-cell-selection="props">
        <q-td :props="props">
          <q-checkbox v-model="props.selected" />
        </q-td>
      </template>
    </q-table>
    Ответ написан
    1 комментарий
  • Как выделять данные в столбце таблицы различными цветами?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Определить классы для выделения текста:

    .waiting { background: yellow; }
    .working { background: green; }
    .completed { background: blue; }

    Определить, какому тексту какой класс соответствует:

    const highlight = {
      'Ожидание': 'waiting',
      'Работа': 'working',
      'Завершено': 'completed',
    };

    Дальше остаётся эти классы назначить кому надо.

    Класс получает элемент внутри ячейки:

    <el-table-column label="Процесс">
      <template #default="{ row: { process } }">
        <span :class="highlight[process]">{{ process }}</span>
      </template>
    </el-table-column>

    Или, класс получает сама ячейка таблицы:

    const cellClassName = ({ column, row }) =>
      column.property === 'process'
        ? (highlight[row.process] ?? '')
        : '';

    <el-table
      :cell-class-name="cellClassName"
      ...
    >
    Ответ написан
  • Как изменить иконку календаря по умолчанию у date picker element plus?

    0xD34F
    @0xD34F Куратор тега Vue.js
    prefix-icon="calendar-icon"

    Да ну? В документации говорится, что это должна быть не строка, а компонент. Давайте будем делать, как сказано.

    UPD. Документацию с первого раза полностью прочитать не осилил, как подсказывают в комментариях - строку указывать всё-таки можно. Окей, вот строка с именем компонента.
    Ответ написан
  • Как добавить иконку в Select ElementPlus?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Разберитесь с версией vue, для которой смотрите примеры кода.

    - <template slot="prefix">
    + <template #prefix>
    Ответ написан
    Комментировать
  • Как изменять цвет текста в progress bar'е?

    0xD34F
    @0xD34F Куратор тега CSS
    Ответ написан
    Комментировать
  • Как отрендерить календарь, чтобы числа дней выводились в соответствии с днями недели?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Отдельные циклы для чисел за текущий и предыдущий месяцы (кстати, а где у вас следующий?) не нужны. Чтобы получить число, надо не на счётчик цикла смотреть, а на дату - начальным значением будет первое число месяца минус количество дней, прошедших с последнего понедельника. Цикл крутить надо не до конца месяца, а немного дальше - чтобы общее количество чисел было кратно семи (т.е., чтобы в последней неделе не было отсутствующих дней) и всегда одно и то же (чтобы размер календаря не зависел от отображаемого месяца). Вот так.
    Ответ написан
    Комментировать
  • Как добавить/ удалить класс каждые 3 секунды в Vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const blocks = ref(Array.from({ length: 5 }, (_, i) => (-~i) ** 2));
    const active = ref(0);
    
    function next() {
      active.value = (active.value + 1 + blocks.value.length) % blocks.value.length;
    }
    
    let intervalId = null;
    onMounted(() => intervalId = setInterval(next, 500));
    onUnmounted(() => clearInterval(intervalId));

    <div
      v-for="(n, i) in blocks"
      v-text="n"
      :class="[ 'box-item', { active: i === active } ]"
    ></div>

    Конечно, зашивать в стили цвета блоков и их количество - все эти :nth-child - не круто. Лучше сделать компонент, принимающий массив цветов и создающий блоки на его основе. Соответственно, вместо класса будет назначаться цвет фона напрямую, как-то так:

    <div
      v-for="(n, i) in colors"
      :style="{ backgroundColor: i === active ? n : '' }"
      ...
    Ответ написан
    2 комментария
  • Как убрать фокус с компонента DateTimePicker при нажатии на ok?

    0xD34F
    @0xD34F Куратор тега Vue.js
    function onVisibleChange(state) {
      if (!state) {
        document.activeElement.blur();
      }
    }

    <el-date-picker
      @visible-change="onVisibleChange"
      ...
    Ответ написан
    Комментировать
  • Почему не обновляется пропс?

    0xD34F
    @0xD34F Куратор тега Vue.js
    почему при изменении даты передаваемой в пропс не обновляется значение в самом компоненте таймера?

    Встречный вопрос - почему вы решили, что внутреннее состояние компонента обновляться должно? Покажите, где вы обновляете targetDate при изменении props.date. Нет, можете себя не утруждать - ничего такого у вас нет.

    Не надо никакого targetDate, рассчитываем дни-часы-минуты-секунды сразу на основе props.date - так при изменении props.date не придётся предпринимать никаких дополнительных телодвижений, всё посчитается как надо при следующем вызове updateCountdown. Вот как-то так.
    Ответ написан
    Комментировать
  • Как убрать scroll у body при открытии модальных окон через vue watch?

    0xD34F
    @0xD34F Куратор тега Vue.js
    .no-overflow {
      overflow: hidden;
    }

    mounted() {
      this.$watch(
        () => this.isModalAddVisible || this.activeId,
        val => document.body.classList.toggle('no-overflow', val),
        { immediate: true }
      );
    },

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

    0xD34F
    @0xD34F Куратор тега Vue.js
    Данные слайдов сложить в массив. Сделать вычисляемое свойство - данные всех слайдов кроме верхнего. Создать верхний слайд, создать остальные слайды на основе вычисляемого свойства. Если нужна анимация перемещения, завернуть слайды в transition-group. Вот так всё просто.
    Ответ написан
    1 комментарий
  • Как динамически добавлять текстовые поля в форму редактирования строки таблицы с использованием Quasar?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сложить имена основных полей в массив.

    Сделать вычисляемое свойство, представляющее имена дополнительных полей - надо получить список ключей editedItem и выкинуть из него имена основных полей.

    В диалоговом окне сделать v-for по массиву дополнительных полей.

    Всё.
    Ответ написан
    Комментировать
  • Как получить свойство из props drilling по открытию модального окна?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Не надо никаких v-model, кого показывать в модальном окне - отправляйте наверх эту информацию вместе с событием. Свойство, управляющее видимостью модального окна - пусть оно вместо логического значения хранит id или объект или что там у вас должно показываться в окне, если не null, значит открываем окно. Вот так всё просто.

    UPD. Вот вариант с v-model, конечно только на уровне таблицы, в строках всё по-прежнему.

    UPD. А вообще, можно полностью отказаться от прокидывания событий наверх. Таблицу исполняем в более общем виде - пусть принимает массив с описанием столбцов, а содержимое ячеек задаётся через слоты, имена которых определяются на основе имён столбцов (по умолчанию выводят данных как есть). В этом случае кнопку можно определить там же, где создаётся экземпляр таблицы. Как это может выглядеть - ваш вариант с отдельным компонентом строки (и, соответственно, прокидыванием в него слотов из компонента таблицы), или, без ненужного усложнения.
    Ответ написан
    1 комментарий
  • Добавил элементы в массив в local storage, при обновлении страницы компоненты пропадают с экрана, но остаются в local storage, как это исправить?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const addCard = (cardName) => {
      cards.value.push({
        id: Date.now(),
        component: cardName,
        order: cards.value.length + 1,
        isRequired: false
      })
    }

    Что такое cardName? Не то, что вам, судя по имени параметра, кажется. Это не имя, а сам объект компонента. И вы его потом в localStorage засовываете. Так что методы setup и render теряются.

    Сложите компоненты в объект:

    const components = {
      ShortTextCard,
      LongTextCard,
      SingleQuestionCard,
      MultiQuestionCard,
    };

    Передавайте в addCard их имена:

    - @click="addCard(ShortTextCard)"
    + @click="addCard('ShortTextCard')"

    Когда надо экземпляр компонента создать, доставайте объект компонента по его имени из упомянутого выше объекта:

    - :is="card.component"
    + :is="components[card.component]"
    Ответ написан
    1 комментарий
  • Как совместить переход по вкладкам из element plus и vue-router?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Лучше никак.

    Так что сперва о том, как надо. Вместо вкладок используем меню - оно умеет работать с роутером:

    <el-menu mode="horizontal" router :default-active="$route.name">
      <el-menu-item
        v-for="n in $router.getRoutes()"
        v-text="n.name"
        :index="n.name"
        :route="n"
      />
    </el-menu>
    <router-view />

    Ну а вкладки... Делаем вычисляемое свойство, представляющее активный маршрут, геттер - возвращает имя, сеттер - по имени выполняет переход:

    computed: {
      activeRouteName: {
        get() {
          return this.$route.name;
        },
        set(name) {
          this.$router.push({ name });
        },
      },
    },

    Используем это свойство для управления вкладками. Контент у всех вкладок одинаковый - <router-view>, но рендерить будем его только в активной вкладке. Вот такой получается говнокод:

    <el-tabs v-model="activeRouteName">
      <el-tab-pane v-for="{ name: n } in $router.getRoutes()" :label="n" :name="n">
        <router-view v-if="activeRouteName === n" />
      </el-tab-pane>
    </el-tabs>
    Ответ написан
    Комментировать
  • Как в el-table вставить нужный мне id, для перехода на страницы?

    0xD34F
    @0xD34F Куратор тега Vue.js
    handleEdit(row){

    @click="handleEdit(scope.$index, scope.row)"

    Сколько параметров получает метод handleEdit? А сколько передаёте ему в обработчике клика? Устраните это печальное несоответствие.

    path:'/protocol_information/:id/edit/',
    params:{
        id:row.id
    }

    Вместо path должен быть name. Конечно, если таковой указан при определении маршрута.

    Или, вырезаете params и вставляете нужный id сразу в строку:

    path: `/protocol_information/${row.id}/edit/`,
    Ответ написан