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

    0xD34F
    @0xD34F Куратор тега Vue.js
    <RatingSelect v-model="rating" />

    const props = defineProps({
      modelValue: {
        type: Number,
        required: true,
      },
      maxRating: {
        type: Number,
        default: 10,
      },
    });
    
    const emit = defineEmits([ 'update:modelValue' ]);
    
    const selected = computed({
      get: () => props.modelValue,
      set: val => emit('update:modelValue', val),
    });

    <li v-for="n in maxRating">
      <label>
        <input type="radio" :value="n" v-model="selected">
        {{ n }}
      </label>
    </li>
    Ответ написан
  • Как сократить код во vue.js?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      buttons: [
        { className: 'btn1', text: 'Limit' },
        { className: 'btn2', text: 'Market' },
      ],
      active: 0,
    }),

    <button
      v-for="(n, i) in buttons"
      v-text="n.text"
      :class="[ 'btn', n.className, { 'active-btn': i === active } ]"
      @click="active = i"
    ></button>

    или даже так (это если у кнопок числа в классах btn* действительно идут по порядку)

    data: () => ({
      buttons: [ 'Limit', 'Market' ],
      active: 'Limit',
    }),

    <button
      v-for="(n, i) in buttons"
      :class="`btn btn${i + 1} ${n === active ? 'active-btn' : ''}`"
      @click="active = n"
    >{{ n }}</button>
    Ответ написан
    Комментировать
  • Как отследить клик на кластере vue-yandex-map?

    0xD34F
    @0xD34F Куратор тега Яндекс.Карты
    Вешать обработчик клика на экземпляр компонента смысла нет - он такого события не порождает. Придётся обращаться непосредственно к кластеризатору:

    <YandexClusterer
      @vue:mounted="onClustererMounted"
      ...

    methods: {
      onClustererMounted(e) {
        e.component.exposed.events.add('click', обработчикКлика);
      },
      ...

    Чтобы не ловить клики с обычных меток, надо у них запретить всплытие соответствующих событий (@click.stop).

    https://stackblitz.com/edit/vue-8tmom1?file=src%2F...
    Ответ написан
    3 комментария
  • Нужно закрыть один попап при открытии другого, как сделать?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Вместо отдельных свойств на каждый попап сделайте одно - имя открытого:

    data: () => ({
      openedPopup: null,
    }),
    methods: {
      togglePopup(popup) {
        this.openedPopup = this.openedPopup === popup ? null : popup;
      },
    },

    @click="togglePopup('search')"

    v-show="openedPopup === 'search'"
    Ответ написан
    1 комментарий
  • Как закрасить дробные части такого индикатора?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Градиентом нарисовать:

    const { filledColor: F, emptyColor: E, ...props } = defineProps({
      value: Number,
      maxValue: Number,
      segments: {
        type: Number,
        default: 5,
      },
      filledColor: {
        type: String,
        default: 'red',
      },
      emptyColor: {
        type: String,
        default: 'black',
      },
    });
    
    const background = val =>
      val >= 1 ? F :
      val <= 0 ? E :
                 `linear-gradient(to right, ${F}, ${F}, ${val * 100}%, ${E} ${val * 100}%)`;

    <div class="rating">
      <div
        v-for="i in segments"
        :style="{ background: background(value / maxValue * segments - i + 1) }"
        class="rating-segment"
      ></div>
    </div>
    Ответ написан
    Комментировать
  • Как изменить родительское значение с использованием дочернего значения VUE JS?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      count: 0,
    }),
    computed: {
      totalOfItem() {
        return this.count * this.price;
      },
    },
    watch: {
      totalOfItem(val, oldVal) {
        this.$emit('clicked', val - oldVal);
      },
    },

    <button @click="count--">sell</button>
    <button @click="count++">buy</button>
    Ответ написан
    Комментировать
  • Как на vue3 создать multy-checkbox?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Как засунуть значения выбранных чекбоксов в массив - рассказывается в документации.

    Значение для чекбокса "выбрать всё" будет вычисляемым. Ничего не выбрано - false, всё выбрано - true, для остальных вариантов undefined, при котором в true будет выставляться indeterminate. Также у него будет сеттер - если попытаться назначить true, то выбранными должны стать все чекбоксы; если false, то никто.

    Вот так:

    const items = ref([
      { id:  69, title:  'hello, world!!' },
      { id: 187, title:  'fuck the world' },
      { id: 666, title: 'fuck everything' },
    ]);
    
    const checked = ref([ 187 ]);
      
    const isAllChecked = computed({
      get: () => ({
        0: false,
        [items.value.length]: true,
      })[checked.value.length],
      set: val => checked.value = val ? items.value.map(n => n.id) : [],
    });

    <div>
      <label>
        <input
          type="checkbox"
          v-model="isAllChecked"
          :indeterminate.prop="isAllChecked === undefined"
        >
        <b>Check all</b>
      </label>
    </div>
    <div v-for="n in items" :key="n.id">
      <label>
        <input type="checkbox" v-model="checked" :value="n.id">
        {{ n.title }}
      </label>
    </div>
    Ответ написан
    3 комментария
  • Как остановить setInterval в vue 3 watch?

    0xD34F
    @0xD34F Куратор тега Vue.js
    После очистки clearInterval он чудесно продолжает работать.

    Брехня.

    Не продолжает.

    Или не он.

    О каком интервале речь?

    У вас их несколько.

    На каждое изменение длины массива - новый интервал.

    Может, не надо запускать новый, если один уже есть?
    Ответ написан
    Комментировать
  • Как остановить таймер?

    0xD34F
    @0xD34F Куратор тега Vue.js
    clearInterval из функции stopTheTimer результата необходимого не показал

    А что такое stopTheTimer? Должно быть, метод компонента. Давайте посмотрим:

    data() {
      <...>
    },
    mounted() {
      <...>
    },
    stopTheTimer() {
      clearInterval(this.interval);
    }

    Не могу назвать себя большим знатоком vue, но я точно слышал, будто методы должны находиться в methods, а не непосредственно в объекте настроек.
    Ответ написан
    3 комментария
  • Как получить выбранный select в списке v-for?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Добавить select'у поддержку директивы v-model:

    props: {
      modelValue: {
        type: String,
        default: '',
      },
      ...

    <select
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    >
      <option
        v-for="n in options"
        v-text="n.label"
        :value="n.value"
      ></option>
    </select>

    В родительском компоненте, сделать свойство selected вместо числа массивом и хранить там выбранные значения:

    data: () => ({
      selected: Array(10).fill(null),
      ...
    }),
    methods: {
      getValue(index) {
        this.active = index;
        console.log(this.selected[index]);
      },
    },

    <div
      v-for="(n, i) in selected"
      class="test__item"
      :class="{ test__item_active: i === active }"
    >
      <span @click="getValue(i)">элемент списка</span>
      <Select v-model="selected[i]" :options="options" />
    </div>
    Ответ написан
    Комментировать
  • Как обновить computed свойство profilesSorting с помощью watch?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Не надо никакого watch, фильтрацию выполняйте прямо в computed:

    const profilesSorting = computed(() => profiles
      .value
      .filter(n => n.id === filters.value.id)
      .sort(...)
      .slice(...)
    );
    Ответ написан
  • VueJS, при добавлении option сбивается selected по умолчанию. Как убрать этот эффект?

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

    Не "несмотря на то", а "потому". Пробел и пустая строка - не одно и то же.

    А вообще, ерундой какой-то занимаетесь. Может, стоит освоить использование v-model?
    Ответ написан
    5 комментариев
  • Как обратиться к ключу объекта?

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

    Не нужно.

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

    Дочерний компонент: this.$emit('do-something').
    Родительский компонент:

    <child-component :object="objects.a" @do-something="doSomething('a')" />
    <child-component :object="objects.b" @do-something="doSomething('b')" />
    <!--> или <-->
    <child-component v-for="(v, k) in objects" :object="v" @do-something="doSomething(k)" />

    methods: {
      doSomething(key) {
        // чего-то делаете
      },
      ...

    Или даже проще, без ключей. Так как, по вашим же словам, ключ вы передаёте, чтобы

    затем пройтись по objects и при совпадении ключей (a, b или c) выполнить действия над значением

    , то почему бы сразу не обращаться к нужному значению?

    <child-component :object="objects.a" @do-something="doSomething(objects.a)" />
    <child-component :object="objects.b" @do-something="doSomething(objects.b)" />
    <!--> или <-->
    <child-component v-for="n in objects" :object="n" @do-something="doSomething(n)" />

    Ещё можно отправлять из дочернего компонента наверх сам объект: this.$emit('do-something', this.object). Тогда не придётся дублировать обращение к нему в родителе:

    <child-component :object="objects.a" @do-something="doSomething" />
    <child-component :object="objects.b" @do-something="doSomething" />
    <!--> или <-->
    <child-component v-for="n in objects" :object="n" @do-something="doSomething" />
    Ответ написан
    Комментировать
  • Как сделать рекурсию для списка комментариев?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Функция, превращающая плоский массив в дерево:

    function createTree({
      arr,
      idKey = 'id',
      parentKey = 'parentId',
      childrenKey = 'children',
    }) {
      const tree = Object.fromEntries(arr.map(n => [ n[idKey], { ...n, [childrenKey]: [] } ]));
      return Object.values(tree).filter(n => !tree[n[parentKey]]?.[childrenKey].push(n));
    }

    Рекурсивный компонент v-tree, выводящий древовидные данные:

    props: {
      items: {
        type: Array,
        default: () => [],
      },
      maxdepth: {
        type: Number,
        default: Infinity,
      },
    },

    <ul v-if="Array.isArray(items) && items.length && maxdepth">
      <li v-for="n in items" :key="n.id">
        {{ n.value }}
        <v-tree :items="n.children" :maxdepth="maxdepth - 1" />
      </li>
    </ul>
    Ответ написан
    5 комментариев
  • Как работать с обновлением в инпуте при сортировке элементов?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Не обновляйте данные, пока фокус не будет потерян. Типа, v-model.lazy.

    Или можете слушать событие input и дёргать метод focus у поля ввода, это заставит (ну, такое должно быть поведение по умолчанию) браузер выполнить прокрутку к элементу (если вдруг недостаточно, можно перед фокусом ещё и scrollIntoView вызвать). Типа так.
    Ответ написан
    1 комментарий
  • Почему во Vue3 не срабатывает computed, когда меняется ref?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const current = ref(props.value);

    Так, ref, хорошо.

    emits("change", current);

    Этот ref отдаёте родителю. Странно, но допустим.

    А что в родителе?

    @change="changeCount"

    Слушаете change, окей.

    function changeCount(value) {
      count.value = value;
    }

    Но при этом зачем-то устанавливаете в качестве значения одного ref'а другой ref, полученный из дочернего компонента. Это как?

    Отправляйте из дочернего компонента число вместо ref'а:

    emits("change", current); ---> emits("change", current.value);
    Ответ написан
  • Как поменять значение при фокусе?

    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"
      ...
    >

    https://play.vuejs.org/#eNp9kkFv1DAQhf/K1JdkpTQL6m...
    Ответ написан
    Комментировать
  • Почему не меняется 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>
    Ответ написан
    Комментировать