Vue -router - Как отменить операции, когда пользователь нажимает на ссылки меню - PullRequest
0 голосов
/ 11 апреля 2020

Не указано c до Vue. js, но до Javascript Одностраничных приложений. Если у вас есть форма и довольно длительное действие отправки, например, сохранение чего-либо. Операция отправки должна что-то сохранить, а затем нажать на новый маршрут для сообщения об успехе.

В ожидании результата пользователь нажимает на другую ссылку и уходит.

См. Эту скрипку:

https://jsfiddle.net/hajbgt28/4/

const Home = { 
  template: '<div><button @click="submit">Save and go Bar!</button></div>',
  methods: {
     async submit() {
            await setTimeout(() => {
           this.$router.push("/bar");
        }, 5000);
     }
  }
};
const Foo = { template: '<div>Foo</div>' }
const Bar = { template: '<div>Bar</div>' }

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '/', component: Home },
    { path: '/foo', component: Foo },
    { path: '/bar', component: Bar }
  ]
})

new Vue({
    router,
  el: '#app',
  data: {
    msg: 'Hello World'
  }
})
  1. Нажмите Домой
  2. Нажмите кнопку
  3. Сразу нажмите «Foo», вы увидите «Foo»
  4. Подождите несколько секунд
  5. Страница меняется на "Бар"

У меня есть два решения:

  • Я могу проверить в операции отправки, если я все еще на маршруте, который я ожидаю, и продолжайте, только если пользователь все еще находится на этой странице. Проверять это каждый раз довольно сложно
  • Отключить все ссылки на странице во время загрузки. Но это делает страницу бесполезной, пока операция не будет завершена.

Какова наилучшая практика для подобных ситуаций?

Ответы [ 3 ]

2 голосов
/ 12 апреля 2020

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

  1. Предполагая идентифицируемые действия отправки, сохранить идентификатор результата операции ( т.е. сохранить идентификатор таймера из возвращаемого значения setTimeout в вашем примере ).
  2. Добавить обработчик beforeRouteLeave к компоненту для отмены действие отправки ( т.е. очистить идентификатор таймера в вашем примере ).
const Home = {
  methods: {
    submit() {
      this.timerId /* 1 */ = setTimeout(() => {
        this.$router.push("/bar");
      }, 5000);
    }
  },
  beforeRouteLeave (to, from, next) {
    clearTimeout(this.timerId) /* 2 */
    next()
  }
};

обновлено jsfiddle

1 голос
/ 11 апреля 2020

Вот одна идея: создать компонент, который предоставляет (используя Vue s provide / inject API):

  1. Функция, которая запускает операцию. Это вызывается при отправке формы. Он обеспечивает whenDone обратный вызов, который либо выполняется, либо игнорируется, в зависимости от того, отменена ли операция.
  2. Функция, которая отменяет все ожидающие операции. Функция отмены может быть вызвана, когда пользователь уходит.

Реализация может выглядеть так:

const CancellableOperationProvider = {
  name: "CancellableOperationProvider",
  props: {},
  data: () => ({
    pendingOperations: []
  }),
  /*
   * Here we provide the theme and colorMode we received
   * from the props
   */
  provide() {
    return {
      $addOperation(func) {
        this.pendingOperations.push(func);
        func(function whenDone(callback) {
          if (this.pendingOperations.includes(func)) callback();
        });
      },
      $cancelAllOperations() {
        this.pendingOperations = [];
      }
    };
  },
  render() {
    return this.$slots.default[0];
  }
};

Использование будет выглядеть следующим образом:

const Home = { 
  template: '<div><button @click="submit">Save and go Bar!</button></div>',
  inject: ['$addOperation', '$cancelAllOperations'],
  methods: {
    async submit() {
      this.$addOperation(whenDone => {
        await setTimeout(() => {
          whenDone(() => this.$router.push("/bar"));
        }, 5000);
      });
    }
  }
};

Затем вы можете добавить навигационную охрану к маршрутизатору Vue, чтобы вызывать $cancelAllOperations после нажатия любой ссылки. Поскольку $cancelAllOperations доступен только через API inject, вам нужно будет создать компонент, который обязательно добавит навигационный щит к маршрутизатору Vue после монтирования и удалит его при размонтировании. Дайте мне знать, если это не сработает - я давно не делал Vue.

0 голосов
/ 14 апреля 2020

Я использовал ответ от tony19, чтобы найти решение, которое соответствует моим потребностям в случаях использования без setTimeout:

const Home = { 
  template: '<div><button @click="submit">Save and go Bar!</button></div>',
  data() {
    return {
        onThisPage: true
    }
  },
  beforeRouteLeave(to, from, next) {
    this.onThisPage = false;
    next();
  },
  methods: {
     submit() {
           setTimeout(() => {
           if (this.onThisPage) {
                this.$router.push("/bar");
           }
        }, 5000);
     }
  }
};

См. Здесь: https://jsfiddle.net/ovmse1jg/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...