From b2429abde2fec36eb28b8d8efe89a4a1446f0457 Mon Sep 17 00:00:00 2001
From: zrh122 <1229550935@qq.com>
Date: Tue, 21 May 2019 00:08:56 +0800
Subject: [PATCH 1/4] fix(router-view): add passing props to inactive component
---
examples/keepalive-view/app.js | 61 +++++++++++++++++++++++++++++++
src/components/view.js | 62 +++++++++++++++++++++++---------
test/e2e/specs/keepalive-view.js | 11 +++++-
3 files changed, 116 insertions(+), 18 deletions(-)
diff --git a/examples/keepalive-view/app.js b/examples/keepalive-view/app.js
index 37563aa32..935b66a9e 100644
--- a/examples/keepalive-view/app.js
+++ b/examples/keepalive-view/app.js
@@ -29,6 +29,48 @@ const Home = { template: '
home
' }
const ViewWithKeepalive = { template: '' }
+const Parent = { template: '' }
+
+const RequiredProps = {
+ template: 'props from route config is: {{msg}}
',
+ props: {
+ msg: {
+ type: String,
+ required: true
+ }
+ }
+}
+
+const savedSilent = Vue.config.silent
+const savedWarnHandler = Vue.config.warnHandler
+
+const CatchWarn = {
+ template: `{{catchedWarn ? 'catched missing prop warn' : 'no missing prop warn'}}
`,
+ data () {
+ return {
+ catchedWarn: false
+ }
+ },
+ beforeRouteEnter (to, from, next) {
+ let missPropWarn = false
+ Vue.config.silent = false
+ Vue.config.warnHandler = function (msg, vm, trace) {
+ if (/Missing required prop/i.test(msg)) {
+ missPropWarn = true
+ }
+ }
+ next(vm => {
+ vm.catchedWarn = missPropWarn
+ })
+ },
+ beforeRouteLeave (to, from, next) {
+ // restore vue config
+ Vue.config.silent = savedSilent
+ Vue.config.warnHandler = savedWarnHandler
+ next()
+ }
+}
+
const router = new VueRouter({
mode: 'history',
base: __dirname,
@@ -80,6 +122,23 @@ const router = new VueRouter({
]
}
]
+ },
+ {
+ path: '/config-required-props',
+ component: Parent,
+ children: [
+ {
+ path: 'child',
+ component: RequiredProps,
+ props: {
+ msg: 'ok'
+ }
+ }
+ ]
+ },
+ {
+ path: '/catch-warn',
+ component: CatchWarn
}
]
})
@@ -96,6 +155,8 @@ new Vue({
/with-guard2
/one/two/child1
/one/two/child2
+ /config-required-props/child
+ /catch-warn
diff --git a/src/components/view.js b/src/components/view.js
index 23d48b883..378443b7d 100644
--- a/src/components/view.js
+++ b/src/components/view.js
@@ -39,17 +39,32 @@ export default {
// render previous view if the tree is inactive and kept-alive
if (inactive) {
- return h(cache[name], data, children)
+ const cachedData = cache[name]
+ const cachedComponent = cachedData && cachedData.component
+ if (cachedComponent) {
+ // #2301
+ // pass props
+ if (cachedData.configProps) {
+ passProps(cachedComponent, data, cachedData.route, cachedData.configProps)
+ }
+ return h(cachedComponent, data, children)
+ } else {
+ // render previous empty view
+ return h()
+ }
}
const matched = route.matched[depth]
- // render empty node if no matched route
- if (!matched) {
+ const component = matched && matched.components[name]
+
+ // render empty node if no matched route or no config component
+ if (!matched || !component) {
cache[name] = null
return h()
}
- const component = cache[name] = matched.components[name]
+ // cache component
+ cache[name] = { component }
// attach instance registration hook
// this will be called in the instance's injected lifecycle hooks
@@ -81,25 +96,38 @@ export default {
}
}
- // resolve props
- let propsToPass = data.props = resolveProps(route, matched.props && matched.props[name])
- if (propsToPass) {
- // clone to prevent mutation
- propsToPass = data.props = extend({}, propsToPass)
- // pass non-declared props as attrs
- const attrs = data.attrs = data.attrs || {}
- for (const key in propsToPass) {
- if (!component.props || !(key in component.props)) {
- attrs[key] = propsToPass[key]
- delete propsToPass[key]
- }
- }
+ const configProps = matched.props && matched.props[name]
+ // pass props
+ if (configProps) {
+ // add route and config props to cache data
+ extend(cache[name], {
+ route,
+ configProps
+ })
+ passProps(component, data, route, configProps)
}
return h(component, data, children)
}
}
+function passProps (component, data, route, configProps) {
+ // resolve props
+ let propsToPass = data.props = resolveProps(route, configProps)
+ if (propsToPass) {
+ // clone to prevent mutation
+ propsToPass = data.props = extend({}, propsToPass)
+ // pass non-declared props as attrs
+ const attrs = data.attrs = data.attrs || {}
+ for (const key in propsToPass) {
+ if (!component.props || !(key in component.props)) {
+ attrs[key] = propsToPass[key]
+ delete propsToPass[key]
+ }
+ }
+ }
+}
+
function resolveProps (route, config) {
switch (typeof config) {
case 'undefined':
diff --git a/test/e2e/specs/keepalive-view.js b/test/e2e/specs/keepalive-view.js
index 68a38ef48..4a8c56c03 100644
--- a/test/e2e/specs/keepalive-view.js
+++ b/test/e2e/specs/keepalive-view.js
@@ -9,7 +9,7 @@ module.exports = {
browser
.url('http://localhost:8080/keepalive-view/')
.waitForElementVisible('#app', 1000)
- .assert.count('li a', 7)
+ .assert.count('li a', 9)
.click('li:nth-child(1) a')
.assert.containsText('.view', 'index child1')
@@ -44,6 +44,15 @@ module.exports = {
.click('li:nth-child(7) a')
.assert.containsText('.view', 'index child2')
+ // missing props in nested routes with keep alive
+ // https://github.com/vuejs/vue-router/issues/2301
+ .click('li:nth-child(8) a')
+ .assert.containsText('.view', 'props from route config is: ok')
+ .click('li:nth-child(9) a')
+ .assert.containsText('.view', 'no missing prop warn')
+ .click('li:nth-child(8) a')
+ .assert.containsText('.view', 'props from route config is: ok')
+
.end()
}
}
From ae0e02a14d0763eb8fe13a7dca5a5f5ccc20b339 Mon Sep 17 00:00:00 2001
From: Eduardo San Martin Morote
Date: Wed, 15 Jan 2020 12:02:35 +0100
Subject: [PATCH 2/4] test(keep-alive): add more cases for props
---
examples/keepalive-view/app.js | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/examples/keepalive-view/app.js b/examples/keepalive-view/app.js
index 935b66a9e..341fed97e 100644
--- a/examples/keepalive-view/app.js
+++ b/examples/keepalive-view/app.js
@@ -27,12 +27,14 @@ const IndexChild2 = { template: 'index child2
' }
const Home = { template: 'home
' }
-const ViewWithKeepalive = { template: '' }
+const ViewWithKeepalive = {
+ template: ''
+}
-const Parent = { template: '' }
+const Parent = { template: 'msg: {{ msg }}
', props: ['msg'] }
const RequiredProps = {
- template: 'props from route config is: {{msg}}
',
+ template: 'props from route config is: {{ msg }}
',
props: {
msg: {
type: String,
@@ -41,14 +43,15 @@ const RequiredProps = {
}
}
-const savedSilent = Vue.config.silent
-const savedWarnHandler = Vue.config.warnHandler
+// keep original values to restore them later
+const originalSilent = Vue.config.silent
+const originalWarnHandler = Vue.config.warnHandler
const CatchWarn = {
- template: `{{catchedWarn ? 'catched missing prop warn' : 'no missing prop warn'}}
`,
+ template: `{{ didWarn ? 'caught missing prop warn' : 'no missing prop warn' }}
`,
data () {
return {
- catchedWarn: false
+ didWarn: false
}
},
beforeRouteEnter (to, from, next) {
@@ -60,13 +63,13 @@ const CatchWarn = {
}
}
next(vm => {
- vm.catchedWarn = missPropWarn
+ vm.didWarn = missPropWarn
})
},
beforeRouteLeave (to, from, next) {
// restore vue config
- Vue.config.silent = savedSilent
- Vue.config.warnHandler = savedWarnHandler
+ Vue.config.silent = originalSilent
+ Vue.config.warnHandler = originalWarnHandler
next()
}
}
@@ -126,12 +129,13 @@ const router = new VueRouter({
{
path: '/config-required-props',
component: Parent,
+ props: { msg: 'from parent' },
children: [
{
path: 'child',
component: RequiredProps,
props: {
- msg: 'ok'
+ msg: 'from child'
}
}
]
@@ -155,6 +159,7 @@ new Vue({
/with-guard2
/one/two/child1
/one/two/child2
+ /config-required-props
/config-required-props/child
/catch-warn
From 880e6ac229a862426440a82e29478c77162fb281 Mon Sep 17 00:00:00 2001
From: Eduardo San Martin Morote
Date: Wed, 15 Jan 2020 12:08:43 +0100
Subject: [PATCH 3/4] test(keep-alive): adapt tests
---
test/e2e/specs/keepalive-view.js | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/test/e2e/specs/keepalive-view.js b/test/e2e/specs/keepalive-view.js
index 4a8c56c03..59602848e 100644
--- a/test/e2e/specs/keepalive-view.js
+++ b/test/e2e/specs/keepalive-view.js
@@ -9,7 +9,7 @@ module.exports = {
browser
.url('http://localhost:8080/keepalive-view/')
.waitForElementVisible('#app', 1000)
- .assert.count('li a', 9)
+ .assert.count('li a', 10)
.click('li:nth-child(1) a')
.assert.containsText('.view', 'index child1')
@@ -47,11 +47,13 @@ module.exports = {
// missing props in nested routes with keep alive
// https://github.com/vuejs/vue-router/issues/2301
.click('li:nth-child(8) a')
- .assert.containsText('.view', 'props from route config is: ok')
+ .assert.containsText('.view', 'msg: from parent')
.click('li:nth-child(9) a')
+ .assert.containsText('.view', 'msg: from parent\nprops from route config is: from child')
+ .click('li:nth-child(10) a')
.assert.containsText('.view', 'no missing prop warn')
- .click('li:nth-child(8) a')
- .assert.containsText('.view', 'props from route config is: ok')
+ .click('li:nth-child(9) a')
+ .assert.containsText('.view', 'msg: from parent\nprops from route config is: from child')
.end()
}
From f1f10343cfae6222dddc771129eb91d0b0880018 Mon Sep 17 00:00:00 2001
From: Eduardo San Martin Morote
Date: Wed, 15 Jan 2020 12:20:27 +0100
Subject: [PATCH 4/4] refactor(view): rename function
---
src/components/view.js | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/src/components/view.js b/src/components/view.js
index 378443b7d..e24d6fa4e 100644
--- a/src/components/view.js
+++ b/src/components/view.js
@@ -45,7 +45,7 @@ export default {
// #2301
// pass props
if (cachedData.configProps) {
- passProps(cachedComponent, data, cachedData.route, cachedData.configProps)
+ fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps)
}
return h(cachedComponent, data, children)
} else {
@@ -97,21 +97,20 @@ export default {
}
const configProps = matched.props && matched.props[name]
- // pass props
+ // save route and configProps in cachce
if (configProps) {
- // add route and config props to cache data
extend(cache[name], {
route,
configProps
})
- passProps(component, data, route, configProps)
+ fillPropsinData(component, data, route, configProps)
}
return h(component, data, children)
}
}
-function passProps (component, data, route, configProps) {
+function fillPropsinData (component, data, route, configProps) {
// resolve props
let propsToPass = data.props = resolveProps(route, configProps)
if (propsToPass) {