Ответы пользователя по тегу Vue.js
  • Как получить данные маркеров, которые находятся в области видимости карты (vue-yandex-map)?

    0xD34F
    @0xD34F Куратор тега Яндекс.Карты
    Подписаться на события инициализации карты и изменения её границ. Получить границы видимой области карты. Перебрать массив данных, на основе которых создаются маркеры, проверяя, как координаты маркеров соотносятся с границами видимой области. Как-то так:

    <yandex-map
      ref="map"
      @map-was-initialized="onBoundsChange"
      @boundschange="onBoundsChange"
      ...
    >
      <ymap-marker
        v-for="n in markersData"
        ...
      >

    methods: {
      onBoundsChange() {
        const bounds = this.$refs.map.myMap.getBounds();
        this.markersData.forEach(n => {
          if (
            bounds[0][0] < n.coords[0] && n.coords[0] < bounds[1][0] &&
            bounds[0][1] < n.coords[1] && n.coords[1] < bounds[1][1]
          ) {
            // ...
          }
        });
      },
      ...
    Ответ написан
    Комментировать
  • Почему не получается передать пользовательское событие родительскому компоненту?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Всё получается, всё передаётся.

    метод testemit компонента question не отрабатывает

    А должен? Нет, не должен - вы его нигде не вызываете. Как и не используете в качестве обработчика событий - вижу, что $emit('testemit') есть, а вот @testemit="testemit" отсутствует.
    Ответ написан
  • Как очищать все поля формы поиска, кроме одного?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сделать observable объект, содержащий ссылку на экземпляр компонента, в котором последний раз осуществлялся пользовательский ввод. Установить наблюдение за этой ссылкой, и если значение не совпадает с текущим экземпляром - сбрасывать значение input'а:

    const lastEdited = Vue.observable({ instance: null });

    props: [ 'value' ],
    methods: {
      onInput(e) {
        this.$emit('input', e.target.value);
        lastEdited.instance = this;
      },
    },
    created() {
      this.$watch(() => lastEdited.instance, val => {
        if (val && val !== this) {
          this.$emit('input', '');
        }
      });
    },
    beforeDestroy() {
      if (lastEdited.instance === this) {
        lastEdited.instance = null;
      }
    },

    <input :value="value" @input="onInput">

    https://jsfiddle.net/jLw096zm/

    Или можно шину событий применить. Если случилось изменение input'а пользователем, кидать событие, в качестве аргумента передавать ссылку на экземпляр компонента, в обработчике сравнивать значение аргумента и this, если не совпали - очищать input:

    const eventBus = new Vue();

    props: [ 'value' ],
    methods: {
      onInput(e) {
        this.$emit('input', e.target.value);
        eventBus.$emit('clear-other-inputs', this);
      },
    },
    created() {
      const clear = e => e !== this && this.$emit('input', '');
      eventBus.$on('clear-other-inputs', clear);
      this.$on('hook:beforeDestroy', () => eventBus.$off('clear-other-inputs', clear));
    },

    <input :value="value" @input="onInput">

    https://jsfiddle.net/jLw096zm/1/
    Ответ написан
    Комментировать
  • Почему не удается получить актуальное значение переменной из Pinia в компоненте?

    0xD34F
    @0xD34F Куратор тега Vue.js
    имеется pinia такого вида
    <...>
    export const useSearchStore = () => {

    Ну и где тут Pinia? Где вызов defineStore?

    const { search, updateSearchQuery } = useSearchStore();

    Так нельзя:

    Note that store is an object wrapped with reactive, meaning there is no need to write .value after getters but, like props in setup, we cannot destructure it

    Вы вообще как, документацию пробовали открывать?

    Исправляем:

    Стор:

    const useSearchStore = defineStore('search', () => {
      const search = ref('');
      const setSearch = val => search.value = val;
      return { search, setSearch };
    });

    Компонент search input:

    const searchStore = useSearchStore();
    const search = computed({
      get: () => searchStore.search,
      set: searchStore.setSearch,
    });

    <input v-model.trim="search">

    Компонент search:

    Не надо слушать никаких событий из search input, не надо трогать стор, уберите это всё отсюда.

    Корневой компонент:

    const searchStore = useSearchStore(); 
    watch(() => searchStore.search, val => console.log(val));
    Ответ написан
  • Как использовать computed внутри v-for?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Никак не использовать. Хотите тут computed - вместо одного значения пусть предоставляет массив:

    const names = computed(() => list.map(n => (n.main ?? n.default).name));

    <div v-for="n in names">
      {{ n }}
    </div>
    Ответ написан
    Комментировать
  • Как в Vue реализовать анимацию пунктов меню с приростом задержки для каждого пункта?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Поставьте значение animation-delay в зависимость от индекса в v-for:

    v-for="(n, i) in items"
    :style="{ 'animation-delay': i * 0.5 + 's' }"

    UPD. Вынесено из комментариев:

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

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

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

    <select>
      <template v-for="n in options">
        <option>
          <slot name="option" :option="n">{{ n }}</slot>
        </option>
      </template>
    </select>

    Снаружи:

    <v-select :options="countries">
      <template #option="{ option }">{{ option.name }}</template>
    </v-select>

    https://jsfiddle.net/w6nuzamx/
    Ответ написан
    2 комментария
  • Не давно начала изучать VUE, какие компоненты правильные?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Правильно так, как вам удобно.

    А ещё, чтобы научиться делать правильно, надо сперва сделать неправильно.

    Так что реализовываете все варианты, какие только сможете придумать.

    Если в реализованном что-то не устраивает, всегда можно оформить вопрос (конечно, сперва погуглив) - вот есть такой-то компонент, решает такую-то задачу, мне в нём не нравится то-то и то-то, какие есть способы сделать лучше?

    Когда решите таким образом задач сорок-пятьдесят, начнёт приходить понимание, как делать правильно.
    Ответ написан
    Комментировать
  • Как избавиться от повторных вызовов метода в шаблоне?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сделайте отдельный компонент, который будет принимать getDayinLoop(worker.wrdays, mday) как параметр.
    Ответ написан
    Комментировать
  • Как передать ивент из одного компонента в другой?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Если говорить именно о передаче событий, то гуглите, что такое шина событий. Но вообще, стоит подумать, а правда ли оно вам надо. Возможно, ваша задача может быть решена иначе:

    Первый компонент - внутри emit, снаружи обработчик события.

    Второй компонент - внутри watch на параметр, снаружи привязка значения этого параметра (значение обновляется в обработчике события первого компонента); или, внутри метод, снаружи ref (вызываете метод в обработчике события первого компонента).
    Ответ написан
    Комментировать
  • Почему при использовании vue3-mq возникает ошибка 'Property "$mq" was accessed during render but is not defined on instance'?

    0xD34F
    @0xD34F Куратор тега Vue.js
    vue3-mq

    this.$mq

    Что по этому поводу имеет сказать документация:

    $mq has been removed as a global property and must now be injected into components that require it
    Ответ написан
    Комментировать
  • Как кастомизировать datepicker в библиотеке element plus?

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

    Иконки убираются с помощью css.

    "Плейсхолдер" делается через дополнительную обёртку (UPD. Или его можно оформить как кастомную иконку).
    Ответ написан
    Комментировать
  • Как создать динамические поля ввода vue3?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const createTopic = () => ({
      text: '',
      subtopics: [ createSubTopic() ],
    });
    
    const createSubTopic = () => ({
      text: '',
    });
    
    const topics = reactive([ createTopic() ]);

    <div v-for="(topic, iTopic) in topics">
      <div>
        <div>
          Topic #{{ iTopic + 1 }}:
          <input v-model="topic.text">
        </div>
        <div v-for="(subtopic, iSubtopic) in topic.subtopics">
          Subtopic #{{ iTopic + 1 }}.{{ iSubtopic + 1 }}:
          <input v-model="subtopic.text">
          <button v-if="iSubtopic" @click="topic.subtopics.splice(iSubtopic, 1)">x</button>
        </div>
      </div>
      <button @click="topic.subtopics.push(createSubTopic())">Add subtopic</button>
    </div>
    <button @click="topics.push(createTopic())">Add topic</button>
    Ответ написан
    1 комментарий
  • Как в один столбец таблицы вывести значения из объекта?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <template v-for="v, k in tableData">
      <tr>
        <td>{{ k }}</td>
      </tr>
      <tr v-for="n in v">
        <td>{{ n.name }}</td>
      </tr>
    </template>
    Ответ написан
    Комментировать
  • Как изменять значение в зависимости от нажатой кнопки с определенным шагом?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      value: 1,
      step: 0.25,
    }),
    methods: {
      updateValue(up) {
        const { value, step } = this;
        const rounded = Math[up ? 'floor' : 'ceil'](value / step) * step;
        this.value = rounded + step * (up ? 1 : -1);
      },
    },

    <input v-model.number="value">
    <button @click="updateValue(0)">-</button>
    <button @click="updateValue(1)">+</button>
    Ответ написан
  • Как сделать так чтобы в value компонента TreeSelect от ElementPlus попадали все выделенные элементы, а не только корневой?

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

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

    watch(values, (newValues, oldValues) => {
      const addedValue = newValues.find(n => !oldValues.includes(n));
      if (addedValue) {
        const findAncestorValues = (arr, val, values = []) =>
          (Array.isArray(arr) ? arr : []).reduce((found, n) => {
            if (!found) {
              values.push(n.value);
              found = n.value === val ? [...values] : findAncestorValues(n.children, val, values);
              values.pop();
            }
            return found;
          }, null);
    
        values.value = [...new Set([ ...values.value, ...findAncestorValues(data, addedValue) ])];
      }
    });

    Если нежелательно реагировать на какие-либо иные изменения массива выбранных значений, кроме тех, что обусловлены действиями пользователя, то тогда вместо использования watch необходимо слушать у el-tree-select событие обновления массива выбранных значений. При этом, чтобы иметь доступ к предыдущей версии этого массива, надо будет немного поработать руками. Как-то так:

    const oldValues = ref([]);
    
    function onUpdate() {
      const addedValue = values.value.find(n => !oldValues.value.includes(n));
      if (addedValue) {
        // тут всё по-прежнему
      }
    
      oldValues.value = values.value;
    }

    <el-tree-select
      @update:modelValue="onUpdate"
      ...
    Ответ написан
  • Как скрыть все компоненты кроме одного?

    0xD34F
    @0xD34F Куратор тега Vue.js
    В корне дерева комментариев храните идентификатор того, на который в данный момент пишется ответ, отдавайте его через provide / inject во вложенные компоненты, в которых, в зависимости от равенства полученного значения конкретному id, показывайте поле для ответа.

    https://jsfiddle.net/5uw1v9o6/
    Ответ написан
    Комментировать
  • Как отобразить структуру данных в виде таблицы?

    0xD34F
    @0xD34F Куратор тега Vue.js
    А что, нормальные имена свойствам придумать было никак? Зачем все эти attr? Непонятно же ни хрена.

    Чтобы не прописывать отдельно строки с rowspan'ами и без, добавьте в v-for индексы, которые затем проверяйте в v-if ячеек с rowspan'ами - рендерить их нужно только при нулевых значениях.

    Почему выводится только objects[0]? Неужели в objects может быть только один элемент? Заверните то, что сейчас есть в ещё один template, в котором будет v-for по элементам objects.

    Можно немного сократить обращения к вложенным свойствам - для этого деструктурируйте элементы массивов, перебираемых в v-for.

    methods: {
      rowspan: attr1 => attr1.reduce((acc, n) => acc + n.attr3.length + 1, 0),
    },

    <template v-for="obj in objects">
      <template v-for="{ road, attr1, TOTAL } in obj.data">
        <template v-for="({ attr2, attr3, attr4 }, iAttr1) in attr1">
          <tr v-for="(attr3Item, iAttr3) in attr3">
            <td :rowspan="rowspan(attr1)" v-if="!iAttr1 && !iAttr3">{{ road }}</td>
            <td :rowspan="attr3.length" v-if="!iAttr3">{{ attr2 }}</td>
            <td>{{ attr3Item.road }}</td>
            <td>{{ attr3Item.cargo }}</td>
            <td>{{ attr3Item.amount }}</td>
            <td>{{ attr3Item.wo_nds }}</td>
          </tr>
          <tr>
            <td colspan="2">Итого {{ attr2 }}:</td>
            <td>{{ attr4.cargo }}</td>
            <td>{{ attr4.amount }}</td>
            <td>{{ attr4.wo_nds }}</td>
          </tr>
        </template>
        <tr>
          <td colspan="3">Итого {{ road }}:</td>
          <td>{{ TOTAL.cargo }}</td>
          <td>{{ TOTAL.amount }}</td>
          <td>{{ TOTAL.wo_nds }}</td>
        </tr>
      </template>
    </template>

    https://jsfiddle.net/ctnr98v7/4/
    Ответ написан
    3 комментария
  • После добавления v-bind с slot, он пропадает из $slots?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Конечно пропадает, он теперь в $scopedSlots.

    Ну и разберитесь с именами:

    v-bind:header="user"

    v-slot:header="{ user }"

    Привязываете параметр с именем header, а использовать пытаетесь user.
    Ответ написан
    Комментировать
  • Как остановить выполнение функции после выбора значения?

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