Переход страницы входа / выхода маршрутизатора Vue: переход по новому маршруту, когда старый маршрут остается видимым - PullRequest
2 голосов
/ 08 октября 2019

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

1. Держите предыдущий маршрут видимым, пока новый маршрут не перейдет в

Независимо от того, является ли переход скользящим, то, что я пытаюсь здесь, или просто исчезаю;Режим in-out не работает так, как я ожидал, а именно, что существующий маршрут остается видимым до тех пор, пока следующий маршрут не завершит свой переход (например, наложился поверх предыдущего), в точности так, как показано здесь в последнем примере этого раздела. https://vuejs.org/v2/guide/transitions.html#Transition-Modes, показывает две кнопки в режиме in-out. Вместо этого никакого перехода не происходит, но он просто переворачивает маршруты статически в половине заданного времени перехода.

Есть ли какие-либо предостережения с маршрутами и очевидная причина, почему это не будет работать так же, например, что одинrouter-view может удерживать только один, и поэтому вход невозможен?

РЕДАКТИРОВАТЬ 1:

Я понял, что in-out будет на самом деле толькоработайте с position:absolute на обоих элементах, иначе они не будут наложены. Любая идея, как я мог бы элегантно включить такое поведение, потенциально устанавливая эту абсолютную позицию только во время перехода маршрутизатора?

Текущий взлом, который имеет визуальный эффект модального сдвига (mode: in-out) Я смотрюдля: добавление style="position:absolute; z-index:2100" к маршруту диалога. Затем мне нужно изменить базовый переход после его показа, чтобы получить эффект обратного скрытия (mode: out-in).

Также см. EDIT 2 ниже.


2. Создание модальной страницы (маршрута), которая открывается над другой существующей страницей при переходе к

Я попытался взломать это поведение, добавив второй вид маршрутизатора в App.vue

<router-view />
<router-view name="dialog" />

Определенный компонент добавляется к моим маршрутам, как этот

{
    path: 'records/new',
    components: {
      dialog: () => import('layouts/NewRecord.vue')
    },
    children: [
      {
        name: 'new-record',
        path: '',
        component: () =>
          import('src/pages/NewRecord.vue')
      }
    ]
  }

Я не уверен, имеет ли этот подход смысл, но я не мог заставить его работать должным образом. Цель состоит в том, чтобы просто наложить еще один router-view name="dialog всякий раз, когда нажимается «диалоговый» путь, поэтому, пока он может быть анимирован (сдвигается вверх), другой вид маршрутизатора остается видимым ниже. В конце концов, я думаю, что я столкнулся с той же проблемой: после изменения маршрута начальный вид маршрутизатора отбрасывает свой компонент, поскольку путь больше не соответствует текущему местоположению.

В любом случае, есть людис большим опытом и знаниями, поэтому я надеюсь, что смогу проиллюстрировать то, чего я пытаюсь достичь, и мне просто любопытно и благодарно прочитать ваши материалы.

РЕДАКТИРОВАТЬ 2

Я мог бы заставить его работать так, как я хотел, просто с одним, обернутым в пользовательский page-transition компонент. Хотя это и есть хак, и мне нужно было добавить position: absolute к майским макетам страниц, ко всем из них (как компоненту «уходящий», так и «входящий» нужно position: absolute) при показе компонента диалога. Я уверен, что есть лучший способ, но я пока не нашел его.

Пользовательский компонент перехода страницы:

<template>
    <transition :name="name" :mode="mode">
        <slot/>
    </transition>
</template>

<script lang="ts">
  import { Component, Watch } from 'vue-property-decorator'
  import Vue from 'vue'
  import { Route } from 'vue-router'

  @Component({
    components: {}
  })
  export default class PageTransition extends Vue {
    NAME_FADE = 'fade'
    NAME_SLIDE_UP = 'slide-up'
    NAME_SLIDE_DOWN = 'slide-down'
    MODE_OUT_IN = ''
    MODE_IN_OUT = 'in-out'

    name = this.NAME_FADE
    mode = this.MODE_OUT_IN

    @Watch('$route', { immediate: true, deep: true })
    onRouteChanged(newVal: Route, oldVal: Route) {
      if (newVal.meta.transition === 'dialog') {
        this.name = this.NAME_SLIDE_UP
        this.mode = this.MODE_IN_OUT

      } else if (oldVal && oldVal.meta.transition === 'dialog') {
        this.name = this.NAME_SLIDE_DOWN
        // shift next page in immediately below dialog
        this.mode = this.MODE_IN_OUT

      } else {
        // default
        this.name = this.NAME_FADE
        this.mode = this.MODE_OUT_IN
      }
    }

  }
</script>

<style lang="scss" scoped>
  .fade-enter, .fade-leave-to {
    opacity: 0;
  }
  .fade-enter-active, .fade-leave-active {
    transition: all 0.1s ease;
  }


  // start of enter element
  .slide-up-enter {
    transform: translateY(60%);
    opacity: 0;
  }
  .slide-up-enter-active {
    transition: all 0.3s ease-out;
    z-index: 2100;
  }

  // start of leave element
  .slide-up-leave, .slide-up-leave-active {
    opacity: 0;
  }


  // start of leave element
  .slide-down-leave {
    z-index: 2100;
  }
  .slide-down-leave-to {
    transform: translateY(60%);
    opacity: 0;
    z-index: 2100;
  }
  .slide-down-leave-active {
    transition: all 0.3s ease-in;
  }

  // start of enter element
  .slide-down-enter {
    opacity: 0;
  }
  .slide-down-enter-active {
    /* show immediately behind existing page (lower z-index) */
    transition: all 0s;
  }
</style>

Ответы [ 2 ]

0 голосов
/ 20 октября 2019

У меня похожая задача. Я смог завершить его, используя фиксированные контейнеры и z-index shuffle. Я столкнулся с рядом проблем, связанных с прокруткой и вертикальным выравниванием, и, в моем случае, решить его с помощью абсолютной позиции только во время перехода через маршрутизатор было невозможно.

Вот демонстрационная версия: https://kasheftin.github.io/vue-router-in-out-slide-scroll. ТакжеМне пришлось использовать localStorage, чтобы сохранить и восстановить положение прокрутки страницы.

В моем случае содержимое страницы должно быть выровнено по вертикали. Вот почему я не мог использовать один глобальный прокручиваемый контейнер (например, <body>). Переход в режим In-Out работает довольно просто - он просто добавляет содержимое, добавляет некоторые классы, а затем удаляет первого потомка. Это означает, что в середине есть два контейнера страниц рядом, и если один из них высок (и заставляет тело иметь прокрутку), то другой появляется в середине тела и имеет неправильное вертикальное выравнивание.

Так что я просто обернул каждую страницу фиксированным прокручиваемым контейнером. Предположим, у нас есть страницы List и Item, а последняя должна скользить справа и перекрывать список. Тогда анимация справа налево очень проста:

.slide-right-enter-active {
  transition: transform 1s ease;

.slide-right-enter {
  transform: translateX(100%);
}

Анимация слева направо (исчезновение наложения) имеет неправильный z-индекс. Во время анимации у нас есть следующее в DOM:

<transition>
  <Item />
  <List />
</transition>

По умолчанию List будет отображаться над Item, но оно должно быть ниже. Итак, есть правила:

.slideable-page {
  position: fixed;
  overflow: auto;
  z-index: 2;
}

.slide-left-enter {
  z-index: 1;
}

.slide-left-enter-active {
  z-index: 1;
}

.slide-left-leave-active {
  transition: transform 1s ease;
  z-index: 3;
}

.slide-left-leave-to {
  transform: translateX(100%);
}

0 голосов
/ 08 октября 2019

Для вопроса 1: Вы добавили CSS с этим? Переход сам по себе обрабатывает только синхронизацию, вам нужно добавить CSS для перехода на работу (пример: https://vuejs.org/v2/guide/transitions.html#Transitioning-Single-Elements-Components).

.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

Для вопроса 2: я не знаю, правильно ли я понялВаша ситуация, но если бы я это сделал, вот что я бы сделал, используя вложенные маршруты.

layouts / NewRecord.vue

<template>
  <router-view name="dialog"></dialog>
</template> 

Routes

const routes = {
  path: 'records/new',
  component: () => import('layouts/NewRecord.vue'),
  children: [
    {
      path: 'dialog',
      components: {
        dialog: () => import('src/pages/NewRecord.vue'),
      },
    },
  ],
}
...