Ответы пользователя по тегу Vue.js
  • Как реализовать смену текста при переключении между radio button?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      meetupId: null,
      meetupData: null,
    }),
    watch: {
      meetupId(val) {
        fetch(`https://course-vue.javascript.ru/api/meetups/${val}`)
          .then(r => r.json())
          .then(r => this.meetupData = r);
      },
    },

    <label v-for="i in 5">
      <input type="radio" name="meetupId" :value="i" v-model="meetupId">
      {{ i }}
    </label>
    <pre>{{ meetupData }}</pre>
    Ответ написан
    Комментировать
  • Почему не работает v-model кастомной радиокнопки на VUE3?

    0xD34F
    @0xD34F Куратор тега Vue.js
    @update:modelValue="$emit('change', $event.target.value)"

    Да ну? Вы действительно считаете, что у радиокнопок бывает событие update:modelValue?

    Местами поменяйте прослушиваемое и генерируемое, пусть будет

    @change="$emit('update:modelValue', $event.target.value)"


    model: {
      prop: 'modelValue',
      event: 'update:modelValue'
    },

    Этот кусок кода можете вырезать, потому что

    BREAKING: v-bind's .sync modifier and component model option are removed and replaced with an argument on v-model;
    Ответ написан
  • Как представить json для генерации такого списка через v-for?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Как должен выглядеть json...

    Примерно так

    [
      {
        title: '...',
        children: [
          {
            title: '...',
            children: [
              {
                title: '...',
              },
              ...
            ],
          },
          ...
        ],
      },
      ...
    ]


    ...для генерации такого вложенного списка через v-for?

    Одного только v-for недостаточно, нужен рекурсивный компонент

    Vue.component('v-tree', {
      props: [ 'items' ],
      template: `
    <ul v-if="Array.isArray(items) && items.length">
      <li v-for="n in items">
        {{ n.title }}
        <v-tree :items="n.children" />
      </li>
    </ul>`,
    });
    Ответ написан
    Комментировать
  • Как исправить ошибку "app.js:11 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'dispatch')"?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const popup =createApp(App);

    popup.$store.dispatch

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

    А вообще, поскольку экземпляр хранилища у вас рядом импортирован, можно обращаться к нему напрямую - просто store.dispatch.
    Ответ написан
  • Как реализовать поиск по массиву с последующем добавлением класса соответствующим объектам?

    0xD34F
    @0xD34F Куратор тега Vue.js
    computed: {
      bullshitEmails() {
        const search = this.search.trim().toLowerCase();
        return this.emails.map(n => ({
          email: n,
          marked: !!search && n.toLowerCase().includes(search),
        }));
      },
    },

    <ul>
      <li
        v-for="{ email, marked } in bullshitEmails"
        v-text="email"
        :class="{ marked }"
      ></li>
    </ul>
    Ответ написан
    Комментировать
  • Как запустить computed в VUE3?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Ключевое слово в качестве имени переменной - что за бред?
    Как достучаться до параметров из script setup - читаем документацию.
    У вычисляемого свойства нет сеттера - так пусть будет функцией, объект не нужен.

    Исправляем:

    const props = defineProps({
      showBgBlue: {
        type: Boolean,
        default: true,
      },
    });
    
    const mainClass = computed(() => props.showBgBlue ? 'bg-blueGray-50 py-12' : 'bg-white');
    Ответ написан
    5 комментариев
  • Почему при обновлении блока на нем перестает работать mouseover?

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

    loaves: [

    this.loaves[idx] =

    Этих кусков кода достаточно, чтобы понять, какой именно раздел документации вы решили не читать.

    Перезапись элемента массива не отслежена => его свойства не стали реактивными => их изменения не приводят к обновлению DOM. Всё.
    Ответ написан
    Комментировать
  • Как обрезать слишком длинный текст при выводе?

    0xD34F
    @0xD34F Куратор тега Vue.js
    methods: {
      short: (str, maxlen) => str.length <= maxlen ? str : str.slice(0, maxlen) + '...',
    },

    <div v-for="n in items" v-text="short(n.text, 16)"></div>
    Ответ написан
    Комментировать
  • Как избавиться от дублирования заголовков?

    0xD34F
    @0xD34F Куратор тега Vue.js
    computed: {
      columns() {
        return Object.keys(this.fedresurs.find(n => n.items.length)?.items[0] ?? {});
      },
    },

    <table v-for="messages in fedresurs">
      <caption>{{ messages.title }}</caption>
      <thead>
        <tr>
          <th v-for="column in columns">{{ column }}</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in messages.items">
          <td v-for="column in columns">{{ item[column] }}</td>
        </tr>
      </tbody>
    </table>
    Ответ написан
    5 комментариев
  • Как заменить встроенный zoom на кастомный?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Использую yandex-map@beta

    Beta? Зачем пытаться использовать заведомо неготовый инструмент?

    пытаюсь изменить параметр zoom в YandexMap, но не работает, и что-то мне подсказывает, что не всё так просто

    Знаете - да. Не всё так просто. Открыл я исходник компонента, и не смог найти там никакого кода, который бы отвечал за изменение состояния карты при изменении значений параметров. Так что придётся менять zoom вручную, напрямую обращаясь к карте:

    setup() {
      ...
      let map = null;
    
      return {
        ...
        onCreate: e => map = e,
        updateZoom: z => map.setZoom(Math.max(1, Math.min(19, map.getZoom() + z))),
      };
    },

    <yandex-map
      ...
      @created="onCreate"
    />
    ...
    <button @click="updateZoom(+1)">+</button>
    <button @click="updateZoom(-1)">-</button>

    Ну или ждите, пока компонент допилят.
    Ответ написан
    1 комментарий
  • Как связать два input между собой?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      currencies: [
        { title:  'рубль', rate:     1, val: 0 },
        { title: 'доллар', rate: 62.65, val: 0 },
        { title:   'евро', rate: 60.90, val: 0 },
      ],
    }),
    methods: {
      onInput({ rate, val }) {
        this.currencies.forEach(n => n.val = val * rate / n.rate);
      },
    },

    <div v-for="n in currencies">
      <input
        v-model.number="n.val"
        @input="onInput(n)"
        type="number"
        min="0"
      >
      {{ n.title }}
    </div>
    Ответ написан
    Комментировать
  • Как реализовать фильтрацию на vue.js по нескольким параметрам одновременно?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сделаем описания столбцов, по которым допускается фильтрация, и способов фильтрации - имя, русифицированный вариант имени (чтобы показывать его в select'ах), и, у столбцов, тип данных:

    data: () => ({
      filterColumns: [
        [     'name',        'имя', 'string' ],
        [    'count', 'количество', 'number' ],
        [ 'distance', 'расстояние', 'number' ],
      ],
      operations: [
        [    'equal',    'равно' ],
        [ 'contains', 'содержит' ],
        [  'greater',   'больше' ],
        [     'less',   'меньше' ],
      ],
      ...

    Тип данных указываем потому, что значения различных типов сравниваются по-разному. Кстати, определим, как именно:

    data: () => ({
      types: {
        string: {
          equal: (a, b) => a.toLowerCase() === b,
          contains: (a, b) => a.toLowerCase().includes(b),
          greater: (a, b) => a.toLowerCase() > b,
          less: (a, b) => a.toLowerCase() < b,
        },
        number: {
          equal: (a, b) => a === +b,
          contains: (a, b) => `${a}`.includes(b),
          greater: (a, b) => a > +b,
          less: (a, b) => a < +b,
        },
      },
      ...

    На основе описаний столбцов и способов фильтрации создадим select'ы:

    <select v-model="column">
      <option v-for="n in filterColumns" :value="n[0]">{{ n[1] }}</option>
    </select>
    <select v-model="operation">
      <option v-for="n in operations" :value="n[0]">{{ n[1] }}</option>
    </select>

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

    computed: {
      filteredItems() {
        const { items, column } = this;
        const type = this.filterColumns.find(n => n[0] === column)?.[2];
        const filterFn = this.types[type]?.[this.operation];
        const filterVal = this.filterVal.toLowerCase();
    
        return filterFn && filterVal
          ? items.filter(n => filterFn(n[column], filterVal))
          : items;
      },
      ...

    https://jsfiddle.net/8df3z1un/1/
    Ответ написан
    Комментировать
  • Как отобразить два v-for в таблице?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Одного хватит. Который будет работать с вычисляемым свойством, представляющим объединённые данные.
    Ответ написан
    Комментировать
  • Почему v-bind перестает работать со строками?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <card-item :title="Неработающий заголовок"/>

    Понятно. Давайте посмотрим, что относительно назначения директивы v-bind говорит документация:

    Динамически связывает атрибуты тега или входной параметр компонента с выражением.

    Вопрос вам: почему вы решили, будто Неработающий заголовок - это выражение?
    Ответ написан
    3 комментария
  • Как передать в роут уникальные параметры во Vuejs?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Объекты категорий складываете в массив, массив кладёте в хранилище. Маршруту добавляете параметр - идентификатор категории. Пробрасываете его в компонент маршрута, где используете его для извлечения данных категории из хранилища. Всё.
    Ответ написан
    1 комментарий
  • Как обернуть выбранный элемент в другой, или построить вокруг него конструкцию из элементов DOM методами Vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <div class="wrapper" v-if="надо рендерить обёртку">
      ...
      <элемент />
      ...
    </div>
    <элемент v-else />

    Или, если считаете, что "элемент" выглядит слишком сложно, чтобы его копипастить, и при этом не хотите оформлять его как отдельный компонент, пишите render-функцию.
    Ответ написан
    Комментировать
  • Как выводить варианты ответов в случайном порядке?

    0xD34F
    @0xD34F Куратор тега Vue.js
    function shuffle(arr) {
      for (let i = arr.length; --i > 0; ) {
        const j = Math.random() * (i + 1) | 0;
        [ arr[i], arr[j] ] = [ arr[j], arr[i] ];
      }
    
      return arr;
    }

    computed: {
      shuffledAnswers() {
        return shuffle(Object.entries(this.questions[this.idx].answers));
      },
      ...

    <div v-for="[ key, answer ] in shuffledAnswers">
      ...
    Ответ написан
    1 комментарий
  • Как сократить запись в v-bind?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Не надо indexOf, индексы доступны в v-for без каких-либо дополнительных телодвижений:

    <div v-for="(row, iRow) in rows" class="board__rows">
      <div
        v-for="(col, iCol) in columns"
        v-text="col + row"
        :class="[ [ 'white', 'black' ][(iRow ^ iCol) & 1], 'board__square' ]"
      ></div>
    </div>
    Ответ написан
    Комментировать
  • Как добавить сотрудника в список (таблицу)?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Cannot read properties of undefined (reading 'lastname')

    Понятно, смотрим, где есть попытка чтения свойства lastname.

    async addNewEmployee({ commit }, employee) {
        await axios
            .post(`http://127.0.0.1:8000/api/v1/employees/`, {
                lastname: employee.lastname,

    Тоже понятно, смотрим, где вызывается addNewEmployee и что туда передаётся.

    @submit.prevent="addNewEmployee(employee)"

    А вот здесь непонятно - что такое employee? Такого свойства в компоненте нет. Надо добавить. Его содержимым будет то, что сейчас находится в хранилище - firstname, lastname, number - там, в хранилище, этим данным делать нечего.
    Ответ написан
    1 комментарий