Skip to content

Commit 9a672d6

Browse files
jhartman86yyx990803
authored andcommitted
1102: $route returns consistent value across all Vue instances (#1108)
* Issue:1102 - Allow injecting router to discrete Vue instances and ensure the $route (getter) returns consisten value * avoid initializing the router more than once
1 parent fd0224a commit 9a672d6

File tree

5 files changed

+113
-1
lines changed

5 files changed

+113
-1
lines changed

Diff for: examples/discrete-components/app.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import Vue from 'vue'
2+
import VueRouter from 'vue-router'
3+
4+
// 1. Use plugin.
5+
// This installs <router-view> and <router-link>,
6+
// and injects $router and $route to all router-enabled child components
7+
Vue.use(VueRouter)
8+
9+
// 2. Define route components
10+
const Home = { template: '<div>Component: home</div>' }
11+
const Foo = { template: '<div>Component: foo</div>' }
12+
const Bar = { template: '<div>Component: bar</div>' }
13+
14+
// 3. Create the router
15+
const router = new VueRouter({
16+
mode: 'history',
17+
base: __dirname,
18+
routes: [
19+
{ path: '/', component: Home },
20+
{ path: '/foo', component: Foo },
21+
{ path: '/bar', component: Bar }
22+
]
23+
})
24+
25+
// 4. Create extended base Vue with router injected here (all
26+
// children should inherit the same router).
27+
const BaseVue = Vue.extend({ router })
28+
29+
// Discrete components means that a new Vue instance will be created
30+
// and bound on multiple *independent* nodes (eg. one Vue instance
31+
// per node); but the router should act as a singleton and keep all
32+
// instances in sync.
33+
document.querySelectorAll('.app').forEach((node) => {
34+
new BaseVue({
35+
el: node
36+
})
37+
})

Diff for: examples/discrete-components/index.html

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!DOCTYPE html>
2+
<link rel="stylesheet" href="/global.css">
3+
<style>
4+
.inliner {font-size:0;line-height:0;}
5+
.app {font-size:1rem;line-height:1;display:inline-block;padding:1rem;width:33%;border-left:1px solid #f1f1f1;box-sizing:border-box;vertical-align:top;}
6+
.snippet {display:inline-block;padding:5px;background:#f1f1f1;font-size:90%;}
7+
.app.component-view {display:block;width:100%;text-align:center;}
8+
</style>
9+
<a href="/">&larr; Examples index</a>
10+
<div class="inliner">
11+
<div class="app">
12+
<ul>
13+
<li><router-link to="/">/</router-link></li>
14+
<li><router-link to="/foo">/foo</router-link></li>
15+
<li><router-link to="/bar">/bar</router-link></li>
16+
</ul>
17+
$route.path value: <span class="snippet">{{ $route.path }}</span>
18+
</div>
19+
<div class="app">
20+
<ul>
21+
<li><router-link to="/">/</router-link></li>
22+
<li><router-link to="/foo">/foo</router-link></li>
23+
<li><router-link to="/bar">/bar</router-link></li>
24+
</ul>
25+
$route.path value: <span class="snippet">{{ $route.path }}</span>
26+
</div>
27+
<div class="app">
28+
<ul>
29+
<li><router-link to="/">/</router-link></li>
30+
<li><router-link to="/foo">/foo</router-link></li>
31+
<li><router-link to="/bar">/bar</router-link></li>
32+
</ul>
33+
$route.path value: <span class="snippet">{{ $route.path }}</span>
34+
</div>
35+
</div>
36+
<div class="app component-view">
37+
<router-view class="view"></router-view>
38+
$route.path value: <span class="snippet">{{ $route.path }}</span>
39+
</div>
40+
<script src="/__build__/shared.js"></script>
41+
<script src="/__build__/discrete-components.js"></script>

Diff for: examples/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ <h1>Vue Router Examples</h1>
2323
<li><a href="scroll-behavior">Scroll Behavior</a></li>
2424
<li><a href="lazy-loading">Lazy Loading</a></li>
2525
<li><a href="auth-flow">Auth Flow</a></li>
26+
<li><a href="discrete-components">Discrete Components</a></li>
2627
</ul>
2728
</body>
2829
</html>

Diff for: src/index.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export default class VueRouter {
1616
static version: string;
1717

1818
app: any;
19+
apps: Array<any>;
1920
options: RouterOptions;
2021
mode: string;
2122
history: HashHistory | HTML5History | AbstractHistory;
@@ -26,6 +27,7 @@ export default class VueRouter {
2627

2728
constructor (options: RouterOptions = {}) {
2829
this.app = null
30+
this.apps = []
2931
this.options = options
3032
this.beforeHooks = []
3133
this.afterHooks = []
@@ -69,6 +71,13 @@ export default class VueRouter {
6971
`before creating root instance.`
7072
)
7173

74+
this.apps.push(app)
75+
76+
// main app already initialized.
77+
if (this.app) {
78+
return
79+
}
80+
7281
this.app = app
7382

7483
const history = this.history
@@ -89,7 +98,9 @@ export default class VueRouter {
8998
}
9099

91100
history.listen(route => {
92-
this.app._route = route
101+
this.apps.forEach((app) => {
102+
app._route = route
103+
})
93104
})
94105
}
95106

Diff for: test/unit/specs/discrete-components.spec.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Vue from 'vue'
2+
import VueRouter from '../../../src/index'
3+
4+
describe('[Vue Instance].$route bindings', () => {
5+
describe('boundToSingleVueInstance', () => {
6+
it('updates $route on all instances', () => {
7+
const router = new VueRouter({
8+
routes: [
9+
{ path: '/', component: { name: 'foo' }},
10+
{ path: '/bar', component: { name: 'bar' }}
11+
]
12+
})
13+
const app1 = new Vue({ router })
14+
const app2 = new Vue({ router })
15+
expect(app1.$route.path).toBe('/')
16+
expect(app2.$route.path).toBe('/')
17+
router.push('/bar')
18+
expect(app1.$route.path).toBe('/bar')
19+
expect(app2.$route.path).toBe('/bar')
20+
})
21+
})
22+
})

0 commit comments

Comments
 (0)