-
Notifications
You must be signed in to change notification settings - Fork 546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for KeepAlive and Transition in Vue Router 4 #160
Conversation
Looks good. I think that if you want to use a If it was possible to detect if |
@dobromir-hristov I'm not so sure about that. I remember starting out with Vue and thinking how incredibly simple it was to do things like this. Slots and dynamic components are not things you try to use; but making everything look "cool" by adding transitions definitely is. The CSS part of the transition is already enough of a barrier to beginners that adding slots and dynamic components makes this, potentially, a bit of a daunting task for beginners. In my mind it could be the difference between having fun while learning Vue and getting maybe a little too frustrated or feeling a little too overwhelmed. @posva I think this RFC is great in terms of the details for how to support Transition and Keep-Alive. Are there any plans or ideas, though, for abstracting this away from the user a little via transition props on To simplify things for the end-user, I'm thinking of introducing a transition component <deep-transition>
<router-view></router-view>
</deep-transition> I think the user can still use the approach in this RFC, but this would be a simplified, more accessible version when using Vue templates. Also, the <DeepTransition name="fade" mode="out-in">
<Transitionable :activeSlot="slot">
<template #Another>
<h2>Another</h2>
</template>
<template #About>
<h1>About</h1>
</template>
</Transitionable>
</DeepTransition>
…
const vTransition = "vTransition"
function DeepTransition(props, { slots }) {
return slots.default().map(vNode => cloneVNode(vNode, {
[vTransition]: ({ Component, attrs }) => h(Transition, props, {
default: () => [
Component
? (openBlock(), createBlock(Component, mergeProps({ key: 0 }, attrs), null, 16 /* FULL_PROPS */))
: createCommentVNode("v-if", true)
],
_: 1
}, 1024)
}))
}
function Transitionable(props, { slots }) {
const Component = () => slots[props.activeSlot]()
const attrs = { activeSlot: props.activeSlot } // router would go here
const defaultSlot = slots.default || props[vTransition]
const vnode = typeof defaultSlot === 'function'
? defaultSlot({ Component, attrs })
: h(defaultSlot)
return vnode
} I'm sure there are drawbacks, I just figured I would try to push toward simplifying this use case since it was one I clearly remember being a very positive experience when learning Vue. Admittedly, I have only been able to get this to work with functional components (both with and without props bound to the Transitionable component, using provide/inject). With a stateful setup component, it doesn't quite work; what's weird is it errors on the first change with realizing now this only works cause I have slots in there 🤦 ... so is there really no way to make this work? maybe via provide/inject, where DeepTransition provides a render function to descendants which inject the render function and pass in any children to wrap them in |
I wished I could keep the same simplicity as in Vue 2 but the best I could come up with is explicitly passing the <transition name="fade">
<router-view :route="$route" />
</transition> If I could automatically make that when no Adding I also thought about adding specific |
@posva I think I agree with you now after trying to figure out several workarounds. It's just an unfortunate loss of simplicity. Although, I'm not sure an additional DeepTransition component is as confusing. I clearly remember struggling for a while to understand scoped slots and I still see relatively experienced devs confused when they encounter scoped slots in templates (it is definitely much more natural in render functions and obviously once you get it it's super powerful). For the sake of putting one last proposal forward on this, I was able to get this to work: <DeepTransition name="fade" mode="out-in">
<Tabs />
</DeepTransition>
...
const vAdopt = 'vAdopt'
const DeepTransition = ((props, { slots }) => {
const instance = getCurrentInstance()
const defaultNodes = slots.default()
const willBeAdopted = defaultNodes.some(vNode => vAdopt in vNode.type.props || vNode.type.props.includes(vAdopt))
if (willBeAdopted) {
instance.provides[vAdopt] = (defaultSlot) => h(Transition, props, defaultSlot)
return defaultNodes
}
return h(Transition, () => defaultNodes)
})
const Tabs = defineComponent((props) => {
const { activeView } = inject('viewData')
const wrapper = inject(vAdopt, fn => { console.log('no fun'); return fn() })
return () => {
return wrapper(() => activeView.value === 'Another' ? h('h1', "Another") : h('h2', "About"))
}
})
Tabs.props = [vAdopt] The idea here is that the wrapper component (DeepTransition) looks to see if a child wants to adopt it, and if so, provides itself, then the adopting child can place it wherever it needs to. This prevents the unnecessary v-slot boiler plate for otherwise black-box components. However, it's a bit of a hack, and obviously the transition bleeds into the provides chain for the parent (a little additional logic could provide scoping perhaps). If having an additional DeepTransition is a concern, maybe this could be rolled into the built-in Transition and KeepAlive components? |
That's a cool concept but I wish it was inside |
This RFC is now in final comments stage. An RFC in final comments stage means that: The core team has reviewed the feedback and reached consensus about the general direction of the RFC and believes that this RFC is a worthwhile addition to the framework. |
7a0e55d
to
3beadd0
Compare
why i use vue-router-next like this |
If you can't hardcode the transition name because it depends on the
Note: you must add a |
Rendered