Используйте один и тот же компонент с несколькими маршрутами, в зависимости от типа компонента пути - PullRequest
0 голосов
/ 01 ноября 2019

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

  1. LevelOneView: это целевая страница, отображающая только виджет поиска. После настройки запроса он перенаправляется на путь /search и сохраняет запрос в VueX
  2. LevelTwoView: в этом представлении отображается результат запроса. Как только пользователь нажимает на результат, он выводит их на /:id путь
  3. LevelThreeView: в этом представлении отображаются сведения о листинге

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

  1. /search => Перейти к LevelTwoView, без специальных работ
  2. /:city => Местоположение (london, newyork, ...) можно вставить, и он должен перейти к LevelTwoView с запросом, уже настроенным на поиск только в списках, доступных в этом регионе. URL должен быть /search
  3. /:id => Перейти к LevelThreeView, используя id в качестве параметра для запроса на выборку. Это число

Я установил защиту beforeEnter на маршруте /:city, чтобы он проверял, является ли параметр пути числом, и в этом случае он должен перенаправить на LevelThreeView. Это прекрасно работает, если я иду от пути /search к /:id (или даже прямо к пути /:id извне), но если я иду от LevelThreeView к LevelThreeView, это делаетне работает и возвращает эту ошибку:

Uncaught (in promise) undefined
    eval @ vue-router.esm.js?8c4f:2051
    abort @ vue-router.esm.js?8c4f:2082
    eval @ vue-router.esm.js?8c4f:2131
    beforeEnter @ router.js?41cb:43
    iterator @ vue-router.esm.js?8c4f:2120
    step @ vue-router.esm.js?8c4f:1846
    eval @ vue-router.esm.js?8c4f:1847
    eval @ vue-router.esm.js?8c4f:2139
    eval @ main.js?56d7:115
    iterator @ vue-router.esm.js?8c4f:2120
    step @ vue-router.esm.js?8c4f:1846
    step @ vue-router.esm.js?8c4f:1850
    runQueue @ vue-router.esm.js?8c4f:1854
    confirmTransition @ vue-router.esm.js?8c4f:2147
    transitionTo @ vue-router.esm.js?8c4f:2034
    push @ vue-router.esm.js?8c4f:2365
    eval @ vue-router.esm.js?8c4f:2779
    push @ vue-router.esm.js?8c4f:2778
    goToListing @ ListingCard.vue?6c5e:147
    click @ ListingCard.vue?917d:18
    invokeWithErrorHandling @ vue.runtime.esm.js?2b0e:1854
    invoker @ vue.runtime.esm.js?2b0e:2179
    original._wrapper @ vue.runtime.esm.js?2b0e:6911

Я настроил маршрутизатор следующим образом:

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'LevelOne',
      component: LevelOneView,
      beforeEnter: (to, from, next) => {
        // Clear the query
        store.commit('resetQuery');
        return next();
      }
    },
    {
      path: '/search',
      name: 'LevelTwo',
      component: LevelTwoView
    },
    {
      path: '/:city',
      name: 'LevelTwoWithCity',
      component: LevelTwoView,
      beforeEnter(to, _, next) {
        // Strip the leading slash
        let toPath = to.path.replace("/", "").toLowerCase();

        // Check if the path is a number and push the lv3 view
        if (!isNaN(toPath)) {
          console.log("Router: found valid path for lv 3")
          const id = parseInt(toPath);
          console.log(id);
          return next({name: 'LevelThree', params: { id: id }});
        } 

        // Load up the query
        let query = store.getters.getQuery;

        // Get the name of all the regions, as a list, to lower case
        let regions = query.regions.map(el => el.name.toLowerCase());

        // Check if we have a matching one
        if (regions.includes(toPath)) {
          // First, deactivate them all
          query.regions.map(el => el.value = false)

          // Then, activate only the one that matched
          query.regions.filter(el => el.name.toLowerCase().includes(toPath)).map(el => el.value = true);

          // Commit the query
          store.commit('setQuery', query);
        }

        return next();
      }
    },
    {
      path: '/:id',
      name: 'LevelThree',
      component: LevelThreeView,
      beforeEnter(to, from, next) {
        console.log("Inside Level3 beforeEnter");
        next();
      }
    },
    {
      path: '/not-found',
      name: '404',
      component: NotFound,
    },
    {
      path: '*',
      name: '404',
      component: NotFound,
    },
  ]
})

Я новичок в этом, поэтому я могу сделать тривиальную ошибку. Если кто-нибудь может дать мне какие-либо указатели, это будет очень цениться.

Спасибо!

1 Ответ

0 голосов
/ 10 ноября 2019

В итоге мне удалось найти «обходной путь». Для каждого из маршрутов вы можете определить псевдонимы . Поэтому я изменил код, чтобы использовать их, и загрузил все возможные маршруты при запуске:

// Generate the aliases
let cities = myCities.map(el => "/" + el.name.toLowerCase());

// Get the base case (i.e. the first element to have something to match against)
let baseCity = cities.splice(0, 1)[0];

export default new Router({
  ...
  routes: [
    {
      path: '/',
      ...
    },
    {
      path: '/search',
      ...
    },
    {
      path: baseCity,
      name: 'LevelTwoWithCity',
      component: LevelTwoView,
      alias: cities,
      ... // Here I set up the query object to be passed on
    },
    {
      path: '/:id',
      name: 'LevelThree',
      component: LevelThreeView
    },
    {
      path: '*',
      name: '404',
      component: NotFound,
    },
  ]
})

теоретически, это можно реализовать динамически, используя метод addRoutes(), описанный здесь

...