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

    0xD34F
    @0xD34F Куратор тега Vue.js
    Ерундой какой-то пытаетесь заниматься. Сделайте разные компоненты и переключайте их.

    Если всё-таки неймётся перекомпилировать шаблон - есть Vue.compile.
    Ответ написан
    Комментировать
  • Как отложить анимацию элемента transition?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Рендерить элементы с задержкой:

    data: () => ({
      items: [
        { show: false, ... },
        { show: false, ... },
        ...
      ],
    }),
    computed: {
      showItems() {
        return this.items.filter(n => n.show);
      },
    },
    mounted() {
      this.items.forEach((n, i) => setTimeout(() => n.show = true, i * 1000));
    },

    <transition-group name="fade">
      <div v-for="n in showItems" :key="n.id">{{ n }}</div>
    </transition-group>
    Ответ написан
  • Как задавать имя класса в зависимости от индекса в v-for?

    0xD34F
    @0xD34F Куратор тега Vue.js
    :class="{ [`delay-${index}s`]: advantage.notThreeLines }"
    Ответ написан
  • Как запретить обработку стилей в v-html?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <iframe :srcdoc="mailContent"></iframe>
    Ответ написан
  • Почему данные не передаются через eventBus (шину событий)?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Вы уже используете vuex, вот через него данные и гоняйте.

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

    через Vuex я уже сделал, теперь хочу потренироваться на шине событий

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

    в чём моя ошибка понять не могу

    "Ошибка"? Ошибки - у вас их целый ворох.

    Если говорить о тех, из-за которых наблюдаемое поведение отличается от ожидаемого, то это: во-первых, передача данных до того, как экземпляр компонента (окно добавления события) создаётся; во-вторых, подписка на события в диалоговом окне в обработчике клика по кнопке добавления, а не при создании компонента.

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

    В общем, всё очень-очень плохо.
    Ответ написан
  • Правильно ли делать компоненты большими?

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

    Не понимаете. Очевидно, вы не слышали про разделение представления и содержания. Никто никакие "таблицы из 50+ позиций", "записи из блогов" и т.д. в компоненты не зашивает. Данные подгружаются отдельно. И размещаются в заранее подготовленных местах.

    То есть, вместо

    <tr>
    <tr>
    ...
    <tr>

    должно быть

    <tr v-for="n in data">

    loadData() {
      fetch(...).then(r => r.json()).then(r => this.data = r);
    },
    Ответ написан
  • Как создать набор блоков для загрузки изображений?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Компонент input-img

    Вырезаете секцию data, ничего этого не надо. Задача компонента - показывать картинку (если она есть), после загрузки отправлять новую картинку родителю, отправлять родителю запрос на удаление картинки:

    methods: {
      onFileChange(e) {
        const file = e.target.files[0];
        if (file) {
          const reader = new FileReader();
          reader.onloadend = () => {
            const image = new Image();
            image.onload = () => {
              this.$emit('uploaded', {
                file,
                src: image.src,
              });
            };
            image.src = reader.result;
          };
          reader.readAsDataURL(file);
        }
      },
    },

    <i
      v-text="img.src ? 'x' : '+'"
      @click="$emit('remove')"
      ...
    />
    <img
      v-if="img.src"
      :src="img.src"
      ...
    >
    <input type="file" accept="image/*" @change="onFileChange">

    Компонент set-imgs

    Добавим поддержку директивы v-model. В props переименовываете images в value, убираете из дефолтного значения объект с пустыми полями. Добавляете images в computed - в качестве значения будет копия value плюс, если длина value меньше максимально допустимой, тот объект с пустыми полями; сеттер - отправляет родителю images, из которого выкинут пустой объект:

    props: {
      value: Array,
      max: {
        type: Number,
        default: 3,
      },
    },
    computed: {
      images: {
        get() {
          const images = [...this.value];
          if (images.length < this.max) {
            images.push({
              file: null,
              src: null,
            });
          }
          return images;
        },
        set(val) {
          this.$emit('input', val.filter(n => n.file));
        },
      },
    },

    Как в этом случае будет выглядеть добавление/изменение картинки - images заменяется на копию, у которой заменён элемент с указанным индексом. А удаление, соответственно, будет выглядеть как фильтрация, тоже по индексу:

    methods: {
      onUpload(index, img) {
        this.images = this.images.map((n, i) => i !== index ? n : img);
      },
      remove(index) {
        this.images = this.images.filter((n, i) => i !== index);
      },
    },

    Собираем всё вместе:

    <input-img
      v-for="(n, i) in images"
      :img="n"
      @uploaded="onUpload(i, $event)"
      @remove="remove(i)"
    />

    Наконец, использование set-imgs

    data: () => ({
      images: [],
    }),

    <set-imgs v-model="images" :max="5" />

    https://jsfiddle.net/7umwaqfd/
    Ответ написан
  • Как избавиться от ошибки про мутацию при передаче значения в поле редактирования компоненты?

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

    UPD. Например.

    <div id="app">
      <todo-add @todo-new="addNewTodo"></todo-add>
      <pre>{{ todoJson }}</pre>
    </div>

    Vue.component('todo-add', {
      template: `
    <div>
      <input v-model="name" autofocus></input>
      <button @click="add">Add New Todo</button>
    </div>`,
      data: () => ({
        name: '',
      }),
      methods: {
        add() {
          const name = this.name.trim();
          if (name) {
            this.$emit('todo-new', name);
            this.name = '';
          }
        },
      },
    });
    
    new Vue({
      el: '#app',
      data: {
        todoArr: [
          { id: 1, name: 'hello, world!!' },
        ],
      },
      methods: {
        addNewTodo(name) {
          this.todoArr.push({
            id: 1 + Math.max(0, ...this.todoArr.map(n => n.id)),
            name,
          });
        },
      },
      computed: {
        todoJson() {
          return JSON.stringify(this.todoArr, null, 2);
        },
      },
    });

    Ответ написан
  • Почему не работает focus()?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Потому что input всё ещё disabled в тот момент, когда вы дёргаете focus. Используйте nextTick:

    this.isDisabled = false;
    this.$nextTick(() => this.$refs.headerBoardName.focus());
    Ответ написан
  • Vue routers children не работает?

    0xD34F
    @0xD34F Куратор тега Vue.js
    А есть где их отображать? Не забыли добавить router-view в FoodItems?
    Ответ написан
  • Как добавить пустой массив во vue через Vue.set?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Vue.set(this.response.order.ordersItemsInfo[id], 'ordersItemsPropertiesInfo', [])
    Ответ написан
  • Как сделать, что бы при клике изменялось сразу несколько стилей/классов?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      items: [ 'active1', 'active2', 'active3' ],
      active: false,
    }),

    <button @click="active = !active"></button>
    ...
    <div v-for="n in items" :class="{ [n]: active }"></div>
    Ответ написан
    1 комментарий
  • Почему меню не выезжает?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Почему не выезжает? Наверное потому, что корневой компонент, и компонент в котором находится меню - это разные компоненты, не там устанавливаете значение свойства isLeftMenuShowed.

    В целом - дичь дикая, $root.$on, зачем так, кто вам такое посоветовал? Говорите, что меню и компонент с кнопкой соседи - ну так осуществляйте их взаимодействие через родителя, например.
    Ответ написан
    Комментировать
  • Как не позволить функции продвинуться дальше?

    0xD34F
    @0xD34F Куратор тега Vue.js
    await setTimeout

    Бессмысленная операция, setTimeout не возвращает Promise, эвейтить тут нечего.

    Если хотите использовать await вместе с setTimeout, последний придётся явно завернуть в Promise:

    await new Promise(r => setTimeout(r, 1000))

    Кроме того, надо возвращать результаты выполнения функций, например здесь

    .catch((e)=>{this.handleUsersListErrors(e)})

    после того, как catch отработает, вызов getUserCheckList завершается, и created продолжает работу, никакого "не позволить продвинуться" не будет (ну и конечно нелишним будет отметить, что хуки жизненного цикла vue синхронны, так что в любом случае не выйдет "приостановить" выполнение created - в том смысле, чтобы асинхронный код выполнился до начала монтирования экземпляра компонента).

    UPD. Держите пример того, как может выглядеть реализация подобной схемы (в роли "запроса" выступает генерация случайного числа, успешным результатом считается число, попадающее в верхние 10% заданного интервала):

    data: () => ({
      status: 'unknown',
      val: 'empty',
    }),
    methods: {
      getVal() {
        this.status = 'awaiting request answer';
        return new Promise((...r) => {
          setTimeout(() => {
            const max = 10000;
            this.val = Math.random() * max | 0;
            r[+(this.val < max * 0.9)]();
          }, 1000);
        }).catch(this.handleError);
      },
      handleError() {
        this.status = 'ERROR, awaiting new request';
        return new Promise(r => setTimeout(r, 2000)).then(this.getVal);
      },
    },
    async created() {
      await this.getVal();
      this.status = 'OK';
    },

    <div>status: {{ status }}</div>
    <div>value: {{ val }}</div>
    Ответ написан
    Комментировать
  • Как передать значение одного компонента в другой?

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

    https://jsfiddle.net/cfLk1jdu/
    Ответ написан
    Комментировать
  • Почему Vue рендерит только первый элемент?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Потому что в html далеко не всякий тэг может быть самозакрывающимся, и если не может, а вы его так оформили, то он рассматривается браузером как открывающий, и всё, что следует за ним, попадает внутрь элемента. То есть, у вас элемент app имеет дочерний элемент designer, у него тоже есть дочерний элемент - higlighter, у которого внутри context-menu. В таком виде ваш шаблон попадает к Vue.

    Так что закрывайте тэги, или вместо dom-шаблона используйте что-нибудь другое - свойство template, render-функция, однофайловые компоненты.
    Ответ написан
    Комментировать
  • Как передать переменную в другой компонент vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    isBarMenuClicked: false, // эту переменную нужно передать

    Не нужно. Зачем кнопке знать о состоянии меню? - её дело нажиматься и оповещать об этом того, кто находится выше. Делайте по клику $emit('click'), подписывайтесь на событие в родительском компоненте, переключайте там значение переменной, отвечающей за открытость меню и передавайте её в меню как параметр.
    Ответ написан
    Комментировать
  • Почему не отображаются все события из JSON файла, а только некоторые?

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

    Вы вообще как, понимаете, что делает return?

    Уверен, можно написать всё короче раза в три, чем есть сейчас, но разбирать ваш код... Вряд ли кто-то тут на такое сподобится, просто заставим его работать ожидаемым образом. Добавляете метку перед внешним циклом, и объявляете массив, в который будете складывать события. Должно стать так:

    const events = [];
    
    collectEvents:
    for(let z = 0; z < arrOfEvents.length; z++){

    Все return memo заменяете на

    events.push(memo);
    continue collectEvents;

    После внешнего цикла добавляете return events;.
    Ответ написан
    Комментировать
  • Как реализовать обновление состояния в хранилище в реальном времени?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Хранилище:

    state: {
      date: null,
      interval: null,
    },
    mutations: {
      update(state) {
        state.date = new Date();
      },
      start(state) {
        if (!state.interval) {
          state.interval = setInterval(this.commit, 1000, 'update');
        }
      },
      stop(state) {
        if (state.interval) {
          clearInterval(state.interval);
          state.interval = null;
        }
      },
    },

    Компонент:

    computed: {
      timerActive() {
        return !!this.$store.state.interval;
      },
      timeStr() {
        const { date } = this.$store.state;
        return date instanceof Date
          ? [ 'getHours', 'getMinutes', 'getSeconds' ]
              .map(n => `${date[n]()}`.padStart(2, 0))
              .join(':')
          : 'ВРЕМЕНИ НЕТ';
      },
    },
    created() {
      this.$store.commit('start');
    },

    <button @click="$store.commit('start')" :disabled="timerActive">start</button>
    <button @click="$store.commit('stop')" :disabled="!timerActive">stop</button>
    <div>{{ timeStr }}</div>
    Ответ написан
  • Как исправить появление блоков (модалка)?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Разделить компонент на два - для списка и выбранного элемента. Данные передавать в список, из списка эмитить выбранный элемент, который передавать в соответствующий компонент.

    https://jsfiddle.net/5kdqema2/
    Ответ написан