Vue路由器进出页面转换:在旧路由保持可见时转换新路由

Posted

技术标签:

【中文标题】Vue路由器进出页面转换:在旧路由保持可见时转换新路由【英文标题】:Vue router in-out page transition: transition in a new route while old route remains visible 【发布时间】:2020-02-05 06:33:21 【问题描述】:

为了说明我想要实现的目标,同时也分别讨论和了解每种机制,我将问题分为两个独立的挑战:

1.保持之前的路线可见,直到新路线过渡进入

过渡是否在滑动,我在这里尝试什么,或者只是逐渐消失;模式in-out 不像我预期的那样工作,即现有路由保持可见直到下一个路由完成其转换(例如,覆盖在前一个路由上),正如本节最后一个示例中所示https://vuejs.org/v2/guide/transitions.html#Transition-Modes,显示两个具有in-out 模式的按钮。相反,没有发生任何转换,它只是在给定转换时间的一半时静态地翻转路由。

对于路线是否有任何警告以及为什么这不会以相同方式工作的明显原因,例如单个router-view 一次只能容纳一个,因此无法进出?

编辑 1:

我发现in-out 实际上只能在两个元素上使用position:absolute,否则它们不会覆盖。知道如何优雅地包含这种行为,可能仅在路由器转换期间设置该绝对位置吗?

我正在寻找具有视觉上滑模式效果(模式:进出)的当前 hack:将 style="position:absolute; z-index:2100" 添加到对话路线。然后,我需要在显示后更改底层过渡,以获得反向隐藏效果(模式: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>

【问题讨论】:

【参考方案1】:

对于问题 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: 我不知道我是否正确理解了您的情况,但如果我理解了,我会这样做,使用嵌套路由。

布局/NewRecord.vue

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

路线

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

【讨论】:

我的 css 是正确的,但请参阅我添加的 EDIT 1。实际上,in-out 的问题与位置有关。【参考方案2】:

我有一个类似的任务。我能够使用固定容器和 z-index shuffle 来完成它。我遇到了许多与滚动和垂直对齐相关的问题,就我而言,仅在路由器转换期间使用绝对位置来解决它是不可能的。

这是演示:https://kasheftin.github.io/vue-router-in-out-slide-scroll。 此外,我必须使用 localStorage 来保持和恢复页面滚动位置。

在我的情况下,页面内容必须垂直对齐。这就是为什么我不能使用一个全局可滚动容器(例如&lt;body&gt;)。进出模式转换的工作相当简单——它只是附加内容,添加一些类,然后删除第一个孩子。这意味着在中间有两个并排的页面容器,如果其中一个很高(并且强制正文有滚动),那么另一个出现在正文中间并且垂直对齐错误。

所以我只是用固定的可滚动容器包装了每一页。假设我们有一个List 和一个Item 页面,最后一个应该从右侧滑动并覆盖列表。那么,从右到左的动画就很简单了:

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

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

从左到右的动画(覆盖消失)的 z-index 错误。在动画期间,我们在 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%);


【讨论】:

以上是关于Vue路由器进出页面转换:在旧路由保持可见时转换新路由的主要内容,如果未能解决你的问题,请参考以下文章

如果我使用带有电子 js 的 vue 路由器,如何修复空白页?

Vue路由scrollBehavior滚动行为控制锚点

VueJs 路由视图转换

在Vue 3中单击路由器链接时如何在不重新加载页面的情况下切换侧边栏

使用 jQuery Mobile 幻灯片转换保持滚动位置

React中路由操作、页面跳转