Задать вопрос
Ответы пользователя по тегу Vue.js
  • Vue 3 как обратиться к компоненту через this.$refs?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const tree = ref(null)

    Начало уже есть, хорошо. Теперь надо этот tree вернуть из setup'а, чтобы им можно было пользоваться в шаблоне:

    return {
      tree,
      ...

    <el-tree
      ref="tree"
      ...

    Ну а когда захотите получить выбранные значения - tree.value.getCheckedKeys().
    Ответ написан
    1 комментарий
  • Какой есть плагин валидации телефона на vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Это называется не валидация, а маска. Погуглил за вас:

    https://www.npmjs.com/package/v-mask
    https://primevue.org/inputmask/
    https://niksmr.github.io/vue-masked-input/
    Ответ написан
    Комментировать
  • Как в дочернем компоненте узнать, что закончилась асинхронная загрузка данных?

    0xD34F
    @0xD34F Куратор тега Vue.js
    В App.vue я запрашиваю все продукты из БД

    Если продукты должны быть доступны везде, может, тогда стоит сначала их получить, а потом уже инициализировать приложение:

    store.dispatch('GET_PRODUCTS').then(() => {
      new Vue({ ... });
    });

    ??

    Если же отвечать непосредственно на спрошенное - установите наблюдение за значением в хранилище:

    watch: {
      '$store.state.products': {
        immediate: true,
        handler(products) {
          if (products) {
            // можно что-то сделать
          }
        },
      },
    },
    Ответ написан
    1 комментарий
  • Как передать модель в кастомный switch Vue js?

    0xD34F
    @0xD34F Куратор тега Vue.js
    1. Убрать:

      data() {
        return {
          isChecked: false,
        }
      },
      methods: {
        toggleSwitch() {
          this.isChecked = !this.isChecked
          this.$emit('input', this.isChecked)
        },
      },


    2. Добавить:

      props: {
        value: Boolean,
      },


    3. Заменить:

      - :class="{ 'ivu-switch-checked': isChecked }"
      + :class="{ 'ivu-switch-checked': value }"

      - @click.prevent="toggleSwitch"
      + @click.prevent="$emit('input', !value)"


    Ответ написан
    Комментировать
  • Почему при удалении элемента класс check не удаляется?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Потому что кто-то невнимательно читал документацию.

    UPD. Как-то сразу не догадался глянуть js-код. А там, а там... ЭТО ЧТО ЕЩЁ ЗА НА ХРЕН:

    elem.classList.add('check');
    elem.querySelector('input[type="checkbox"]').remove();

    ??

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

    UPD. Как может выглядеть исправленный (и дополненный - редактирование теперь тоже есть) вариант вашего кода:

    data: () => ({
      tasks: [],
      taskId: 0,
      newTaskText: '',
    }),
    methods: {
      addTask() {
        this.tasks.push({
          id: ++this.taskId,
          text: this.newTaskText,
          done: false,
          edit: false,
        });
    
        this.newTaskText = '';
      },
    },

    <ul>
      <li v-for="(n, i) in tasks" :key="n.id" :class="{ check: n.done }" @dblclick="n.edit = !n.done">
        <input type="checkbox" v-if="!n.done" v-model="n.done">
        <input type="text" v-if="!n.done && n.edit" v-model="n.text" @keyup.enter="n.edit = false">
        <template v-else>{{ n.text }}</template>
        <input type="button" class="del" value="+" @click="tasks.splice(i, 1)">
      </li>
    </ul>
    <input type="text" v-model="newTaskText" @keyup.enter="addTask">
    Ответ написан
  • Как правильно настроить слайдер и поп-ап Vuetify?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Не могу закрыть поп-ап

    dialog: [],

    dialog[index]= false

    Кто-то невнимательно читал документацию.

    При нажатии на кнопку, при выборе 3 изображения на превью открывается всегда первое.

    Не всегда, а при первом открытии каждого диалога.

    Кстати, непонятно - а зачем вам три диалоговых окна? Сделайте одно:

    data: () => ({
      slide: null,
      dialog: false,
      ...
    }),
    methods: {
      openDialog(slideIndex) {
        this.slide = slideIndex;
        this.dialog = true;
      },
      ...
    },

    v-row
      v-col(v-for="(n, i) in pictures")
        v-item
          v-img(height="100", width="100", :src="n", @click="openDialog(i)")
      v-col(hidden="")
        v-dialog(v-model="dialog")
          v-carousel(v-model="slide")
            v-carousel-item(v-for="n in pictures")
              v-img(:src="n")
          v-btn(@click="dialog = false") close dialog
    Ответ написан
    1 комментарий
  • Как передать props в компонент во Vue 3 через роутинг?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сначала пара слов о том, как правильно:

    Роутинг для передачи данных в этой ситуации использовать не надо. Подключаете vuex, кладёте массив в хранилище, компонент home никаких параметров не принимает, просто достаёт из хранилища нужные данные и передаёт их в компонент posts:

    <posts :posts="$store.state.posts" />

    Как видите, всё элементарно.

    Передача же "через роутинг" обернётся говнокодерством:

    • Можно сделать маршрут именованным и передавать через params:

      <router-link :to="{ name: 'home', params: { posts } }">home</router-link>

      this.$router.push({
        name: 'home',
        params: {
          posts: this.posts,
        },
      });

      Сразу же очевиден первый недостаток такого способа: в скольких местах осуществляется переход на роут home, столько раз придётся и передавать туда явным образом массив posts, указывая его в params каждого router-link или вызова $router.push. При этом, если переход осуществляется не из корневого компонента, то, чтобы дотянуться до posts, придётся ещё и $root использовать. В случае же, когда пользователь решит осуществить переход посредством адресной строки браузера, то ничего передать не получится.

      Ещё один недостаток станет очевидным после перехода - оказывается, элементы posts превратились в строки. Роутер приводит к строкам значения свойств params (или, если свойство является массивом, к строкам будут приведены его элементы). Так что для корректной передачи ещё придётся и в json данные конвертировать, а в компоненте home этот json парсить - говнокод, как и обещал.

    • Можно прицепить данные к router-view, тогда они будут переданы как параметры в компонент текущего маршрута: <router-view :posts="post" />.

      Тут тоже не всё пройдёт гладко - так передача параметров будет осуществляться в компоненты всех маршрутов, и там, где переданные параметры не описаны, они будут сочтены атрибутами и прицеплены к корневому элементу (если он один; когда несколько - надо явным образом указывать, куда добавлять $attrs). Чтобы передавать что надо только куда надо, можно оформить параметры, передаваемые в router-view, как вычисляемое свойство, значение которого будет зависеть от текущего маршрута:

      computed: {
        routeParams() {
          return что-то, в зависимости от this.$route;
        },
      },

      <router-view v-bind="routeParams" />

    Ответ написан
  • Как сделать добавление tr в таблицу по условию?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Такие есть варианты:

    1. Сделать отдельный tbody для каждой пары строк. Переносите tbody из компонента таблицы в компонент строки - будет там корневым элементом:

      <tbody>
        <tr>... </tr>
        <tr v-if="...">...</tr>
      </tbody>

      Пример.

    2. Сделать компонент строки функциональным - там может быть несколько корневых узлов. Пример.
    3. Отказаться от использования компонента строки, рендерить tr сразу в компоненте таблицы:

      <tbody>
        <template v-for="...">
          <tr>... </tr>
          <tr v-if="...">...</tr>
        </template>
      </body>

      Пример.

    4. Переехать на Vue 3 - там можно сделать компонент с несколькими корневыми узлами. Пример.
    5. Попробовать использовать костыль. Здесь примера не будет - к этой штуке не прикасался и не собираюсь.
    Ответ написан
    Комментировать
  • Как создать динамический шаблон при компонентном подходе без создания и дальнейшего перебора массива в массиве в еще одном массиве?

    0xD34F
    @0xD34F Куратор тега Vue.js
    А откуда там взяться массиву в массиве и т.д.? Нужен массив объектов, которые описывают поля формы, а также объект с данными формы (это то, что сейчас у вас представлено отдельными свойствами). Всё:

    data: () => ({
      formData: {},
      formMeta: [
        { name: 'phone', title: 'Телефон', type: 'text', placeholder: 'Телефон' },
        { name: 'email', title: 'E-mail', type: 'text', placeholder: 'E-mail' },
        { name: 'address', title: 'Адрес', type: 'text', placeholder: 'Адрес' },
        ...
      ],
    }),

    this.$emit('save-contact', this.formData);

    <div v-for="n in formMeta">
      <span class="form__other-title">{{ n.title }}</span>
      <div class="form__other-data">
        <input
          v-model="formData[n.name]"
          :type="n.type"
          :placeholder="n.placeholder"
        >
      </div>
    </div>
    Ответ написан
  • Как создать табы на vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    работать с dom напрямую плохая практика

    Не всегда. Зависит от задачи.

    Пусть компонент табов принимает в качестве параметров массив значений, описывающих табы и значение, обозначающее активный таб:

    props: [ 'items', 'value' ],

    В данные компонента положим стили для элемента, изображающего подчёркивание активного таба:

    data: () => ({
      sliderStyles: null,
    }),

    Создадим сами табы и элемент подчёркивания:

    <ul class="tabs">
      <li
        v-for="n in items"
        :key="n.value"
        @click="$emit('input', n.value)"
        class="tabs-item"
      >{{ n.text }}</li>
    </ul>
    <div
      class="tabs-slider"
      :style="sliderStyles"
    ></div>

    Элементу подчёркивания (.tabs-slider) зададим абсолютное позиционирование и transition.

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

    mounted() {
      this.$watch(
        'value',
        value => {
          const index = this.items.findIndex(n => n.value === value);
          const el = this.$el.querySelectorAll('.tabs-item')[index];
          this.sliderStyles = el
            ? {
                left: `${el.offsetLeft}px`,
                width: `${el.offsetWidth}px`,
              }
            : null;
        },
        {
          immediate: true,
        }
      );
    },

    https://jsfiddle.net/vsr5tLue/
    Ответ написан
    Комментировать
  • Как во vue js сделать аналог foreach?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Никакой "аналог foreach" тут не нужен.

    Сделайте компонент: получает через слот контент, который надо показывать/скрывать; содержит свойство, в зависимости от значения которого переданный контент отображается или нет; переключает значение свойства, управляющего видимостью контента, по клику. Как-то так:

    data: () => ({
      opened: false,
    }),

    <div class="dropdown">
      <div class="dropdown-header" @click="opened = !opened">
        <slot name="header" :opened="opened">
          {{ opened ? 'CLOSE' : 'OPEN' }}
        </slot>
      </div>
      <div v-if="opened" class="dropdown-content">
        <slot name="content"></slot>
      </div>
    </div>

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

    0xD34F
    @0xD34F Куратор тега Vue.js
    Обработчик события прицеплен к какому-то непонятному div'у вместо экземпляра компонента. Неудивительно, что он не вызывается.
    Ответ написан
    1 комментарий
  • Как объединить два чарта в Chart.js?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Надо определить две оси Y:

    options: {
      scales: {
        yAxes: [
          { id: 'y1', position: 'left' },
          { id: 'y2', position: 'right' },
        ],
      },
    },

    приложение делается на vue

    Есть vue-chartjs, использование которого для вашего случая может выглядеть так, например.
    Ответ написан
  • Как центрировать карту на маркере по клику на item списка маркеров?

    0xD34F
    @0xD34F Куратор тега Яндекс.Карты
    Свойство coords - переместить из компонента с картой в vuex. Тогда в компоненте элемента списка можно будет делать что-то вроде @click="$store.commit('setCoords', marker.coords)".
    Ответ написан
  • Как сделать сортировку в таблице по отдельной кнопке?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      sortBy: '',
      ...
    }),

    <v-btn @click="sortBy = 'имя_свойства_по_которому_надо_выполнить_сортировку'">click me</v-btn>
    
    <v-data-table :sort-by.sync="sortBy">...</v-data-table>

    Если при повторном клике надо переключать порядок сортировки, тогда так:

    data: () => ({
      sortBy: [],
      sortDesc: [],
      ...
    }),
    methods: {
      sort(colName) {
        const sameCol = this.sortBy[0] === colName;
        const sortDesc = this.sortDesc[0];
    
        this.sortBy = sameCol && sortDesc ? [] : [ colName ];
        this.sortDesc = sameCol && sortDesc ? [] : [ sameCol ];
      },
      ...
    },

    <v-btn @click="sort('имя_свойства_по_которому_надо_выполнить_сортировку')">click me</v-btn>
    
    <v-data-table :sort-by.sync="sortBy" :sort-desc.sync="sortDesc">...</v-data-table>

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

    sort(colName) {
      const index = this.sortBy.indexOf(colName);
      if (index === -1) {
        this.sortBy.push(colName);
        this.sortDesc.push(false);
      } else if (this.sortDesc[index]) {
        this.sortBy.splice(index, 1);
        this.sortDesc.splice(index, 1);
      } else {
        this.$set(this.sortDesc, index, true);
      }
    },

    А вообще, можно сделать совсем просто. Имитируется клик по заголовку указанного столбца, дальше компонент таблицы сам всё исполнит в лучшем виде:

    <v-btn @click="sort('имя_свойства_по_которому_надо_выполнить_сортировку')">click me</v-btn>
    
    <v-data-table ref="table">...</v-data-table>

    methods: {
      sort(colName) {
        const index = this.свойство_описывающее_столбцы_таблицы.findIndex(n => n.value === colName);
        this.$refs.table.$el.querySelector('thead tr').cells[index].click();
      },
      ...
    },
    Ответ написан
    Комментировать
  • Как во vuex передать инстанс яндекс.карты, чтобы в методах компонента Vue можно было по клику добавлять маркеры?

    0xD34F
    @0xD34F Куратор тега Яндекс.Карты
    Не нужно дёргать карту напрямую. Сделайте массив с данными маркеров, заполняйте его по клику, и на его основе создавайте экземпляры компонента маркера:

    import { yandexMap, ymapMarker, loadYmap } from 'vue-yandex-maps';

    components: {
      yandexMap,
      ymapMarker,
    },
    data: () => ({
      coords: null,
      markers: [],
      settings: { /* ... */ },
    }),
    methods: {
      onClick(e) {
        this.markers.push({
          id: 1 + Math.max(0, ...this.markers.map(n => n.id)),
          coords: e.get('coords'),
        });
      },
    },
    async mounted() {
      await loadYmap({ ...this.settings, debug: true });
    
      ymaps.geolocation.get().then(res => {
        this.coords = res.geoObjects.position;
      });
    },

    <yandex-map
      v-if="coords"
      :coords="coords"
      @click="onClick"
    >
      <ymap-marker
        v-for="n in markers"
        :key="n.id"
        :marker-id="n.id"
        :coords="n.coords"
      ></ymap-marker>
    </yandex-map>

    https://jsfiddle.net/f65hraxk/
    Ответ написан
    3 комментария
  • Как правильно добавить фотографии в слайдер Vue Carousel 3D?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      slides: [
        'путь к первой картинке',
        'путь ко второй картинке',
        ...
      ],
    }),

    <slide v-for="(n, i) in slides" :index="i">
      <figure>
        <img :src="n">
      </figure>
    </slide>
    Ответ написан
    Комментировать
  • Как показывать только один компонент, который используется несколько раз?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Родитель всегда общий? Если да, тогда добавьте в него свойство, которое будет указывать, в каком из экземпляров вашего компонента надо отображать дополнительные элементы. В качестве значения можно использовать индекс экземпляра, например (не обязательно, также подойдёт какое-нибудь свойство из объектов с данными, на основе которых создаются экземпляры компонента - главное, чтобы значения были уникальными, типа id):

    data: () => ({
      items: [ ... ],
      active: null,
    }),

    <v-xxx
      v-for="(n, i) in items"
      :показыватьДополнительныйКонтент="active === i"
      @переключитьОтображениеДополнительногоКонтента="active = active === i ? null : i"
      ...

    https://jsfiddle.net/kdg4qevp/

    В противном случае создайте наблюдаемый объект, и поместите свойство, указывающее кого отображать, в него:

    const xxx = Vue.observable({ active: null });

    В свой компонент добавьте вычисляемое свойство, значение которого а) определяет необходимость демонстрации дополнительных элементов; б) зависит от свойства наблюдаемого объекта:

    computed: {
      показыватьДополнительныйКонтент() {
        return xxx.active === this.какоеТоСвойствоСУникальнымЗначением;
      },
    },

    <div v-if="показыватьДополнительныйКонтент">
      ...
    </div>

    Также добавьте в свой компонент метод для переключения отображения дополнительного содержимого:

    methods: {
      переключитьОтображениеДополнительногоКонтента() {
        xxx.active = this.показыватьДополнительныйКонтент
          ? null
          : this.какоеТоСвойствоСУникальнымЗначением;
      },
    },

    <button @click="переключитьОтображениеДополнительногоКонтента">
      {{ показыватьДополнительныйКонтент ? 'hide' : 'show' }}
    </button>

    https://jsfiddle.net/kdg4qevp/1/
    Ответ написан
    1 комментарий
  • Что означают три точки впереди функции во vue шаблоне?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Это означает, что вы не знаете js.

    Да и в целом - плохо понимаете смысл используемых вами слов. Какой шаблон, вы чего? Шаблон vue - это html, который компилируется в render-функцию. А вы что показали?
    Ответ написан
    4 комментария
  • Vuetify - как обратиться к чекбоксам?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Добавляете в компонент свойство, которое будет указывать, случалось ли ваше событие. Если его значение false, тогда ничего не делаете, по умолчанию будет отрендерен чекбокс, если true - передаёте в соответствующий слот что там вам надо:

    data: () => ({
      событиеНаступило: false,
      ...
    }),

    @событие="событиеНаступило = true"

    <v-data-table>
      <template v-if="событиеНаступило" #item.data-table-select>
        здесь размещаете контент, который должен отображаться вместо чекбоксов
      </template>
      ...

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

    <v-data-table>
      <template #item.data-table-select="{ item, isSelected, select }">
        <div v-if="item.событиеНаступило">hello, world!!</div>
        <v-simple-checkbox
          v-else
          :value="isSelected"
          @input="select($event)"
        ></v-simple-checkbox>
      </template>
      ...
    Ответ написан