vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
207.98k stars 33.68k forks source link

Transition + keep alive + router-view #5524

Closed taoyingsong closed 7 years ago

taoyingsong commented 7 years ago

Version

2.2.6

Reproduction link

http://jsfiddle.net/fanaticism1/wtpuevc6/72/

Steps to reproduce

switch the components, the animation does not display correctly when it show. I am not sure whether this issue belongs to vue or vue router.

I write a exmple , but the params '$route.meta.keepAlive' can not get, so I mentioned another question【https://github.com/vuejs/vue-router/issues/1378

What is expected?

The animation display correctly when rendering a component in the router view。

What is actually happening?

The animation does not display correctly when rendering a component in the router view。


no

posva commented 7 years ago

I think you wanted to do this: http://jsfiddle.net/ygjg5znx/ (v-if then v-else)

taoyingsong commented 7 years ago

@posva First thank you for your answer! Yes, the animation is what I hope, but I found that keep-alive is dead。

If I write like this, keep-alive is available but the animation is invalid:

<transition name="router-fade" mode="out-in">
       <div class="main-content">
             <keep-alive >
                  <router-view v-if="$route.meta.keepAlive" @title="setTitle"></router-view>
              </keep-alive>
              <router-view v-if="!$route.meta.keepAlive" @title="setTitle"></router-view>
       </div>
</transition>

If I write this way, the animation is available but keep-alive is invalid:

<transition name="router-fade" mode="out-in">
      <keep-alive v-if="$route.meta.keepAlive">
              <router-view @title="setTitle"></router-view>
      </keep-alive>
      <router-view v-else @title="setTitle"></router-view>
</transition>

I do not know what information is needed to make the problem more clear. Because it involves async request, I do not know how to write a clear demo.

posva commented 7 years ago

mmh I see. Yeah, we cannot use transitions and have granular control over what is kept alive with router-views at the moment. I'm not sure it's on router's or vue's end where we should improve. I'll come back when I have more information

taoyingsong commented 7 years ago

OK, I know .I'm not sure if there is any better solution,but thank you very much ~~ ^_^

posva commented 7 years ago

Ok, so you need to define an include or exclude prop on the keep-alive. At first I thought it didn't work with the router-view 🙂 but that's because you alse have to provide a name property on your view components.

http://jsfiddle.net/1ap6njzn/1 Foo is kept alive but Home is not

Keep in mind that you can generate the list by reading the routes array in your Root component that renders the view. All you need to know about include and exclude is at https://vuejs.org/v2/api/#keep-alive Hope it helps!

taoyingsong commented 7 years ago

I tried it, the animation takes effect, keep-alive also takes effect, but keep-alive takes effect on all the components rendered in the router-view,and I want it to be one.

I saw this in the vue document:

The match is first checked on the component’s own name option, then its local registration name (the key in the parent’s components option) if the name option is not available. Anonymous components cannot be matched against.

The .vue component rendered in the router-view does not seem to have a name, and it can not be imported into the parent. (I tried it briefly and did not work after it was introduced). I do not know where I am not in place。

posva commented 7 years ago

Yeah, the name is necessary. If it doesn't work, I'm sorry, you'll have to ask on the forums

casbloem commented 6 years ago

give your router-view an unique key.. like: :key="$route.name + ($route.params.id || null)"

yiyizym commented 6 years ago

Thank you @casbloem

I solved my problem by doing sth like :

<transition name="router-fade" mode="out-in">
      <keep-alive v-if="$route.meta.keepAlive">
              <router-view @title="setTitle" :key="$route.name + ($route.params.id || null)"></router-view>
      </keep-alive>
      <router-view v-else @title="setTitle" :key="$route.name + ($route.params.id || null)"></router-view>
</transition>
lanpangzhi commented 6 years ago

Is there a solution to this bug?

johnwhelchel commented 6 years ago

@lanpangzhi , this does work. I was able to use the example show in @posva 's fiddle to figure it out. I got it working with something like the following:

<template>
...
      <transition name="router-view-fade" mode="out-in">
        <keep-alive :exclude="Array.from(excludeNames)" :include="includeNames()">
          <router-view :key="$route.params.id"></router-view>
        </keep-alive>
      </transition>
...
</template>

<script>
    export default {
        name: "main-app",
            ...
        components: {...},
        data: function () {
            return {
                excludeNames: new Set(['component-to-exclude-1', 'cte2',...])
            };
        },
        methods: {
            includeNames() {
                return this.$router.options.routes.map(r => r.components.default.name).filter(name => !!name && !this.excludeNames.has(name));
            }
        }
    };
</script>

You many need to adjust includeNames based on how you're router is setup.

johnsoncheg commented 4 years ago

@lanpangzhi , this does work. I was able to use the example show in @posva 's fiddle to figure it out. I got it working with something like the following:

<template>
...
      <transition name="router-view-fade" mode="out-in">
        <keep-alive :exclude="Array.from(excludeNames)" :include="includeNames()">
          <router-view :key="$route.params.id"></router-view>
        </keep-alive>
      </transition>
...
</template>

<script>
  export default {
      name: "main-app",
          ...
      components: {...},
      data: function () {
          return {
              excludeNames: new Set(['component-to-exclude-1', 'cte2',...])
          };
      },
      methods: {
          includeNames() {
              return this.$router.options.routes.map(r => r.components.default.name).filter(name => !!name && !this.excludeNames.has(name));
          }
      }
  };
</script>

You many need to adjust includeNames based on how you're router is setup.

I found that this not work if u u async components

ghostcode commented 3 months ago

Thank you @casbloem

I solved my problem by doing sth like :

<transition name="router-fade" mode="out-in">
      <keep-alive v-if="$route.meta.keepAlive">
              <router-view @title="setTitle" :key="$route.name + ($route.params.id || null)"></router-view>
      </keep-alive>
      <router-view v-else @title="setTitle" :key="$route.name + ($route.params.id || null)"></router-view>
</transition>

cache still work ?