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

    0xD34F
    @0xD34F Куратор тега Vue.js
    Устанавливаете текстовому полю новое значение и отправляете ему событие input, чтобы v-model обновил данные компонента:

    methods: {
      removeLastChar({ target: t }) {
        t.value = t.value.slice(0, -1);
        t.dispatchEvent(new Event('input'));
      },
      ...
    },

    <input
      @focus="removeLastChar"
      ...
    >
    Ответ написан
    Комментировать
  • Почему не меняется style при click?

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

    sortOpen() {
      this.$emit('sortOpen', this.sortWindowOpen = !this.sortWindowOpen);
    },

    <TableControl @sortOpen="addStatic = $event"></TableControl>
    Ответ написан
    5 комментариев
  • Как реализовать смену текста при переключении между 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 недостаточно, нужен рекурсивный компонент

    name: 'v-tree',
    props: [ 'items' ],

    <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
    data: () => ({
      maxlen: 10,
      items: [
        'hello, world!!',
        'fuck the world',
        'fuck everything',
        '1234567890',
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit,',
       ],
    }),
    methods: {
      short1: (str, maxlen) => str.length <= maxlen ? str : str.slice(0, maxlen) + '...',
      short2: (str, maxlen) => str.substring(0, maxlen) + (str.charAt(maxlen) && '...'),
      short3: (str, maxlen) => str.replace(RegExp(`(.{${maxlen}}).+`), '$1...'),
      short4: (str, maxlen) => str.replace(RegExp(`(?<=.{${maxlen}}).+`), '...'),
    },

    <input type="range" min="1" max="20" v-model="maxlen">
    <span>{{ maxlen }}</span>
    
    <div v-for="n in items">
      <div v-text="short1(n, maxlen)"></div>
      <div v-html="short2(n, maxlen)"></div>
      <div :text-content.prop="short3(n, maxlen)"></div>
      <div>{{ short4(n, maxlen) }}</div>
    </div>

    https://jsfiddle.net/dxm0gsnf/
    Ответ написан
    Комментировать
  • Как избавиться от дублирования заголовков?

    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 Куратор тега Яндекс.Карты
    Использую 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 Куратор тега CSS
    Время, которое я задаю, применяется к fadeOut, а вот к runProgress нет

    Окей, посмотрим на эти fadeOut и runProgress:

    this.fadeOut = `fadeOut ${this.time}s linear forwards`,
    this.runProgress = `runProgress ${this.time}s liner forwards`,

    Вам вопрос: чем отличаются эти две строки (конечно, помимо имён анимаций)?

    UPD. А это вообще нормально - всем назначать одно и то же значение? В смысле, в шаблоне эти fadeOut и runProgress используются для задания анимации элементам, у которых есть предок с v-for. Если изменить значение свойства time и добавить в messages новый элемент, то у тех, что были добавлены раньше, изменится длительность анимации. Наверное, стоит вырезать свойства fadeOut и runProgress, элементам messages при создании добавлять актуальное значение свойства time, типа time: this.time, и использовать его при задании стилей:

    methods: {
      getStyle: (name, { time }) => ({
        animation: `${name} ${time}s linear forwards`,
      }),
      ...

    :style="getStyle('fadeOut', message)"

    :style="getStyle('runProgress', message)"
    Ответ написан
    1 комментарий
  • Как выводить варианты ответов в случайном порядке?

    0xD34F
    @0xD34F Куратор тега Vue.js
    function shuffle(arr) {
      for (let i = arr.length; i > 1;) {
        const j = Math.random() * (i--) | 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">
      ...

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

    "answers": {

    Пусть это будет массив. Соответственно, правильный ответ будет обозначаться через индекс.

    import usersData from "../questions.json";

    Не надо импортировать вопросы в компоненте теста, пусть они передаются в него через props.

    selectedAnswer: "",

    Всего один? Этого мало, надо запоминать все полученные ответы.

    count: 5,

    <div v-if="idx < count">

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

    computed:{
      randomQuestions () {
        usersData.sort(() => Math.random() - 0.5)

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

    :disabled="selectedAnswer != ''"

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

    <button
      @click="nextQuestion"

    надо сделать такую же кнопку для перехода к предыдущему вопросу.

    document.querySelectorAll("input").forEach((el) => (el.checked = false));

    Не надо лезть в DOM руками. Чтобы при переходе к следующему вопросу сбрасывать выбор, достаточно пересоздавать элементы, назначив их общему предку ключ, зависящий от индекса (:key="индекс_вопроса"). Но это, конечно, костыльное решение. Правильно будет управлять радиокнопками основываясь на данных, через v-model.

    @change="answered($event)"

    answered(e) {
      this.selectedAnswer = e.target.value;
      if (this.selectedAnswer == this.questions[this.idx].correctAnswer) {
        this.correctAnswers++;

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

    https://jsfiddle.net/0L9ayx1u/1/
    Ответ написан
    1 комментарий