mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-26 23:52:06 +00:00
fix(vue-app): use child transition name when navigating to parent (#6946)
This commit is contained in:
parent
b05d4a74f7
commit
539c865533
@ -111,31 +111,29 @@ function componentOption (component, key, ...args) {
|
||||
return option
|
||||
}
|
||||
|
||||
function mapTransitions (Components, to, from) {
|
||||
function mapTransitions (toComponents, to, from) {
|
||||
const componentTransitions = (component) => {
|
||||
const transition = componentOption(component, 'transition', to, from) || {}
|
||||
return (typeof transition === 'string' ? { name: transition } : transition)
|
||||
}
|
||||
const tComponents = [].concat(Components)
|
||||
|
||||
const fromComponents = from ? getMatchedComponents(from) : []
|
||||
const maxDepth = Math.max(toComponents.length, fromComponents.length)
|
||||
|
||||
// If leaving a child route to a parent, keep the child leave transition
|
||||
while (from && from.matched.length > tComponents.length) { // eslint-disable-line no-unmodified-loop-condition
|
||||
tComponents.push({})
|
||||
const mergedTransitions = []
|
||||
for (let i=0; i<maxDepth; i++) {
|
||||
// Clone original objects to prevent overrides
|
||||
const toTransitions = Object.assign({}, componentTransitions(toComponents[i]))
|
||||
const transitions = Object.assign({}, componentTransitions(fromComponents[i]))
|
||||
|
||||
// Combine transitions & prefer `leave` properties of "from" route
|
||||
Object.keys(toTransitions)
|
||||
.filter(key => typeof toTransitions[key] !== 'undefined' && !key.toLowerCase().includes('leave'))
|
||||
.forEach((key) => { transitions[key] = toTransitions[key] })
|
||||
|
||||
mergedTransitions.push(transitions)
|
||||
}
|
||||
return tComponents.map((Component, i) => {
|
||||
// Clone original object to prevent overrides
|
||||
const transitions = Object.assign({}, componentTransitions(Component))
|
||||
|
||||
// Combine transitions & prefer `leave` transitions of 'from' route
|
||||
if (from && from.matched[i] && from.matched[i].components.default) {
|
||||
const fromTransitions = componentTransitions(from.matched[i].components.default)
|
||||
Object.keys(fromTransitions)
|
||||
.filter(key => fromTransitions[key] && key.toLowerCase().includes('leave'))
|
||||
.forEach((key) => { transitions[key] = fromTransitions[key] })
|
||||
}
|
||||
|
||||
return transitions
|
||||
})
|
||||
return mergedTransitions
|
||||
}
|
||||
<% } %>
|
||||
<% if (loading) { %>async <% } %>function loadAsyncComponents (to, from, next) {
|
||||
|
112
test/e2e/page-transitions.browser.test.js
Normal file
112
test/e2e/page-transitions.browser.test.js
Normal file
@ -0,0 +1,112 @@
|
||||
import Browser from '../utils/browser'
|
||||
import { loadFixture, getPort, Nuxt } from '../utils'
|
||||
|
||||
let port
|
||||
const browser = new Browser()
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let page = null
|
||||
|
||||
const parseEvents = async (page) => {
|
||||
const events = await page.evaluate(() => [...document.querySelectorAll('#transition-events li')].map(li => li.textContent))
|
||||
return events.map(event => event.split('|'))
|
||||
}
|
||||
|
||||
describe('page transitions (browser)', () => {
|
||||
beforeAll(async () => {
|
||||
const config = await loadFixture('page-transitions')
|
||||
nuxt = new Nuxt(config)
|
||||
await nuxt.ready()
|
||||
|
||||
port = await getPort()
|
||||
await nuxt.server.listen(port, 'localhost')
|
||||
|
||||
await browser.start({
|
||||
// slowMo: 50,
|
||||
// headless: false
|
||||
})
|
||||
})
|
||||
|
||||
test('Open /', async () => {
|
||||
page = await browser.page(url('/'))
|
||||
|
||||
expect(await page.$text('h1')).toBe('Index page')
|
||||
})
|
||||
|
||||
test('Root page callbacks', async () => {
|
||||
await page.nuxt.navigate('/callbacks')
|
||||
const events = await parseEvents(page)
|
||||
expect(events).toEqual(
|
||||
[
|
||||
['index', 'beforeLeave'],
|
||||
['index', 'leave'],
|
||||
['index', 'afterLeave'],
|
||||
['callbacks', 'beforeEnter'],
|
||||
['callbacks', 'enter'],
|
||||
['callbacks', 'afterEnter']
|
||||
]
|
||||
)
|
||||
})
|
||||
|
||||
test('Parent -> Child page callbacks', async () => {
|
||||
await page.nuxt.navigate('/callbacks/child')
|
||||
const events = await parseEvents(page)
|
||||
expect(events).toEqual(
|
||||
[
|
||||
['callbacks-child', 'beforeEnter'],
|
||||
['callbacks-child', 'enter'],
|
||||
['callbacks-child', 'afterEnter']
|
||||
]
|
||||
)
|
||||
})
|
||||
|
||||
test('Child -> Parent page callbacks', async () => {
|
||||
await page.nuxt.navigate('/callbacks')
|
||||
const events = await parseEvents(page)
|
||||
expect(events).toEqual(
|
||||
[
|
||||
['callbacks-child', 'beforeLeave'],
|
||||
['callbacks-child', 'leave'],
|
||||
['callbacks-child', 'afterLeave']
|
||||
]
|
||||
)
|
||||
})
|
||||
|
||||
test('Root page transition properties', async () => {
|
||||
await page.nuxt.navigate('/transition-properties')
|
||||
const transitionsData = await page.nuxt.transitionsData()
|
||||
expect(transitionsData.length).toBe(1)
|
||||
expect(transitionsData[0].name).toBe('custom')
|
||||
expect(transitionsData[0].appear).toBe(true)
|
||||
expect(transitionsData[0].css).toBe(false)
|
||||
expect(transitionsData[0].mode).toBe('in-out')
|
||||
expect(transitionsData[0].duration).toBe(3000)
|
||||
})
|
||||
|
||||
test('Parent -> child transition properties', async () => {
|
||||
await page.nuxt.navigate('/transition-properties/child')
|
||||
const transitionsData = await page.nuxt.transitionsData()
|
||||
expect(transitionsData.length).toBe(2)
|
||||
expect(transitionsData[0].name).toBe('custom')
|
||||
expect(transitionsData[1].name).toBe('custom-child')
|
||||
})
|
||||
|
||||
test('Child -> parent transition properties', async () => {
|
||||
await page.nuxt.navigate('/transition-properties')
|
||||
const transitionsData = await page.nuxt.transitionsData()
|
||||
expect(transitionsData.length).toBe(2)
|
||||
expect(transitionsData[0].name).toBe('custom')
|
||||
expect(transitionsData[1].name).toBe('custom-child')
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await nuxt.close()
|
||||
})
|
||||
|
||||
// Stop browser
|
||||
afterAll(async () => {
|
||||
await page.close()
|
||||
await browser.close()
|
||||
})
|
||||
})
|
6
test/fixtures/page-transitions/layouts/default.vue
vendored
Normal file
6
test/fixtures/page-transitions/layouts/default.vue
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<ul id="transition-events"></ul>
|
||||
<Nuxt />
|
||||
</div>
|
||||
</template>
|
3
test/fixtures/page-transitions/page-transitions.test.js
vendored
Normal file
3
test/fixtures/page-transitions/page-transitions.test.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import { buildFixture } from '../../utils/build'
|
||||
|
||||
buildFixture('page-transitions')
|
12
test/fixtures/page-transitions/pages/callbacks.vue
vendored
Normal file
12
test/fixtures/page-transitions/pages/callbacks.vue
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Callbacks page</h1>
|
||||
<NuxtChild />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { createTransitionObject } from '../utils/transition-properties'
|
||||
export default {
|
||||
transition: createTransitionObject('callbacks')
|
||||
}
|
||||
</script>
|
11
test/fixtures/page-transitions/pages/callbacks/child.vue
vendored
Normal file
11
test/fixtures/page-transitions/pages/callbacks/child.vue
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Callbacks child page</h1>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { createTransitionObject } from '../../utils/transition-properties'
|
||||
export default {
|
||||
transition: createTransitionObject('callbacks-child', 'page', 'true')
|
||||
}
|
||||
</script>
|
11
test/fixtures/page-transitions/pages/index.vue
vendored
Normal file
11
test/fixtures/page-transitions/pages/index.vue
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Index page</h1>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { createTransitionObject } from '../utils/transition-properties'
|
||||
export default {
|
||||
transition: createTransitionObject('index')
|
||||
}
|
||||
</script>
|
18
test/fixtures/page-transitions/pages/transition-properties.vue
vendored
Normal file
18
test/fixtures/page-transitions/pages/transition-properties.vue
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Transition properties page</h1>
|
||||
<NuxtChild />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
transition: {
|
||||
name: 'custom',
|
||||
appear: true,
|
||||
css: false,
|
||||
mode: 'in-out',
|
||||
duration: 3000
|
||||
}
|
||||
}
|
||||
</script>
|
18
test/fixtures/page-transitions/pages/transition-properties/child.vue
vendored
Normal file
18
test/fixtures/page-transitions/pages/transition-properties/child.vue
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Transition name child page</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
transition: {
|
||||
name: 'custom-child'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.custom-child-enter-active, .custom-child-leave-active {
|
||||
transition: opacity 1s ease;
|
||||
}
|
||||
</style>
|
34
test/fixtures/page-transitions/utils/transition-properties.js
vendored
Normal file
34
test/fixtures/page-transitions/utils/transition-properties.js
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
const addEvent = (componentName, callbackName, clear = false) => {
|
||||
const ul = document.querySelector('#transition-events')
|
||||
if (clear) {
|
||||
ul.innerHTML = ''
|
||||
}
|
||||
const li = document.createElement('li')
|
||||
li.textContent = `${componentName}|${callbackName}`
|
||||
ul.appendChild(li)
|
||||
}
|
||||
|
||||
export const createTransitionObject = (componentName, transitionName = 'page', child = false) => ({
|
||||
name: transitionName,
|
||||
|
||||
beforeEnter () {
|
||||
addEvent(componentName, 'beforeEnter', child)
|
||||
},
|
||||
enter (el, done) {
|
||||
addEvent(componentName, 'enter')
|
||||
done()
|
||||
},
|
||||
afterEnter () {
|
||||
addEvent(componentName, 'afterEnter')
|
||||
},
|
||||
beforeLeave () {
|
||||
addEvent(componentName, 'beforeLeave', true)
|
||||
},
|
||||
leave (el, done) {
|
||||
addEvent(componentName, 'leave')
|
||||
done()
|
||||
},
|
||||
afterLeave () {
|
||||
addEvent(componentName, 'afterLeave')
|
||||
}
|
||||
})
|
@ -105,6 +105,9 @@ export default class Browser {
|
||||
},
|
||||
storeState () {
|
||||
return page.evaluate($nuxt => $nuxt.$store.state, page.$nuxt)
|
||||
},
|
||||
transitionsData () {
|
||||
return page.evaluate($nuxt => $nuxt.nuxt.transitions, page.$nuxt)
|
||||
}
|
||||
}
|
||||
return page
|
||||
|
Loading…
Reference in New Issue
Block a user