├── .editorconfig ├── .gitignore ├── README.md ├── component.json ├── package.json ├── src ├── index.js ├── overrides.js ├── routing.js └── utils.js └── test ├── common.js └── keep-alive-data.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | npm-debug.log 4 | test/build.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vue-route 2 | ======= 3 | 4 | ## Vue-route is discontinued. Try the official [vue-router](https://github.com/vuejs/vue-router) instead. 5 | 6 | Routing directive for Vue.js, inspired by ng-view. 7 | Based on `v-component` thus benefits from `v-transition`, `keep-alive`, `wait-for`, `transition-mode`. 8 | 9 | Versions 1.5.0+ are made for **Vue.js v0.12+.** 10 | Use older versions for Vue.js v0.11. 11 | 12 | Allows you to declare your routes on the `$root` Vue object: 13 | 14 | ```js 15 | var root = new Vue({ 16 | el: 'body', 17 | 18 | routes: { 19 | '/home': { 20 | componentId: 'fg-home', 21 | isDefault: true 22 | }, 23 | '/items/:item': { 24 | componentId: 'fg-item', 25 | afterUpdate: 'updateHeader', 26 | data: { 27 | defaultColor: '#3453DD' 28 | } 29 | }, 30 | options: { 31 | hashbang: true 32 | } 33 | } 34 | }); 35 | 36 | ``` 37 | 38 | With minimal markup: 39 | 40 | ```html 41 | 42 |
43 | 44 | 45 | ``` 46 | 47 | `vue-route` extends the `v-component` directive by @yyx990803 (on the [vuejs repo](https://github.com/yyx990803/vue/tree/master/src/directives/component.js)). Buy him a coffee if you can. 48 | 49 | ## Get started 50 | 51 | **1.** Install with npm/component(1): `npm i vue-route --save` or `component install ayamflow/vue-route`. 52 | 53 | **2.** Require and install the plugin: 54 | 55 | ```js 56 | var Vue = require('vue'), 57 | route = require('vue-route'); 58 | 59 | Vue.use(route); // BOOM 60 | ``` 61 | 62 | **3.** Put the `
` in your main template. 63 | 64 | **4.** Pass your routes to the `$root` VM of you app (see example above). 65 | 66 | **5.** Profit ! 67 | 68 | ## Transition, keep-alive and other directives 69 | If you want to add custom transitions between your pages, it's recommended to put them on each page's component template. Putting anything on the `v-route` element itself will only be active if you change this element (for instance with a `v-if` directive). 70 | Following the example, that would be: 71 | 72 | ```js 73 |
...
// fg-home component 74 | ``` 75 | 76 | ## Additional infos 77 | 78 | * Routes definition: when you pass your routes to the `$root`, you can pass several properties: 79 | * `componentId`: the Vue.component id for the associated template/VM. 80 | * `beforeUpdate`: a callback (method or name of method on the vm) to call before effectively changing to this routehtml. 81 | * `afterUpdate`: a callback (method or name of method on the vm) to call after effectively having changed to this route. 82 | * `data`: an object (or function returning an object) that will be **merged** with the view's `$data`. This is useful when we need to use the same component for different urls but using different data. 83 | * `isDefault`: boolean indicating wether this page should be the default, in case of non-existing URL. Think of it as the `otherwise` from Angular, so basically a 404 or the home page. 84 | 85 | `beforeUpdate` is a middleware, this means you need to call the `next` function provided as the third argument, to continue routing. This allows to prevent a route based on some condition. 86 | For instance, you can `return` before `next` is called to cancel the route; usefull for an authentication page for instance. 87 | Another instance is to pause the app during loading and calling `next` when everything is loaded, thus resuming the flow. 88 | 89 | Vue is augmented with an additional method, `Vue.navigate(path, [trigger])`. [trigger] is a boolean (defaults to true) that will `pushState` if true, `replaceState` otherwise. 90 | 91 | * The router will emit events on your `$root` VM: `router:started`, `router:beforeUpdate`, `router:afterUpdate`. 92 | 93 | * You can pass a `options` hash to pass configuration to the router: 94 | * `hashbang`: boolean (defaults to false) to use `#!` urls. Note that your links shouldn't include hashbangs, the router handles this. 95 | * `click`: boolean (defaults to true) to automatically bind all click to the router. Not that if `false`, you will need to explicitly call `Vue.navigate` method). 96 | * `base`: string (defaults to '/') to specify the base path. 97 | * `broadcast`: boolean (defaults to false) if true the events will be emitted using the $root `$broadcast` method, so all child VMs will receive the event until a handler `return false;`. If false, it uses `$emit`. 98 | * `debug`: boolean (defaults to false) to activate logging from the directive. 99 | 100 | ## Location context 101 | 102 | When the router emits an event, 2 parameters are passed: `location` and `oldLocation`. Like in Angular, it is an object containing some useful properties: 103 | * `regexp`: the route regexp, such as `/items/:item`. 104 | * `path`: the current path, such as `/items/razor/`. 105 | * `params`: a hash of the params from the route, here `{item: 'razor'}`. 106 | * `componentId`: the componentId associated to the current route. 107 | 108 | ## Route parameters 109 | 110 | Each component used by `v-route` will have its `$data` extended with the `location.params` array (see above). That means that on the route `/items/razor`, `this.$data.$routeParams.item == 'razor'`. 111 | 112 | ## Subroutes 113 | Managing subviews with subroutes like `/route/:firstParam/:secondParam` is userland responsability; you should handle this with a `v-component` or programmatically. 114 | 115 | ## Compatibility note 116 | vue-route supports the same browsers as Vue; however to make it properly work on IE9 you need to add the [HTML5-history-API polyfill](https://github.com/devote/HTML5-History-API). 117 | 118 | ## Contributing 119 | 120 | * Fork & PR on **[dev](https://github.com/ayamflow/vue-route/tree/dev)** branch. 121 | * If possible, add tests to cover the changes. 122 | * Code style: 4 tabs, semicolons. Check the code if in doubt. 123 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-route", 3 | "version": "1.5.1", 4 | "repository": "ayamflow/vue-route", 5 | "description": "Routing directive for Vue.js, inspired by ng-view.", 6 | "main": "src/index.js", 7 | "scripts": [ 8 | "src/index.js", 9 | "src/overrides.js", 10 | "src/routing.js", 11 | "src/utils.js" 12 | ], 13 | "keywords": [ 14 | "vue", 15 | "route", 16 | "router", 17 | "page", 18 | "transition" 19 | ], 20 | "author": "= <=>", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/ayamflow/vue-route/issues" 24 | }, 25 | "dependencies": { 26 | "visionmedia/page.js": "^1.5.0" 27 | }, 28 | "development": { 29 | "dependencies": { 30 | "yyx990803/vue": "^0.11.3", 31 | "substack/tape": "^3.0.2" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-route", 3 | "version": "1.5.1", 4 | "description": "Routing directive for Vue.js, inspired by ng-view.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/prova ./test/**/*.js -b -l phantom -q", 8 | "test-browser": "./node_modules/.bin/prova ./test/**/*.js -b -l chrome" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/ayamflow/vue-route" 13 | }, 14 | "keywords": [ 15 | "vue", 16 | "route", 17 | "router", 18 | "page", 19 | "transition" 20 | ], 21 | "author": "= <=>", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/ayamflow/vue-route/issues" 25 | }, 26 | "devDependencies": { 27 | "prova": "^2.1.2", 28 | "vue": "^0.12.9" 29 | }, 30 | "dependencies": { 31 | "page": "^1.5.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./utils'), 4 | page = require('page'); 5 | 6 | module.exports = function(Vue) { 7 | var component = Vue.directive('_component'), 8 | overrides = require('./overrides')(Vue), 9 | routing = require('./routing')(Vue, page, utils), 10 | _ = Vue.util; 11 | 12 | var routeDefinition = _.extend({ 13 | isLiteral: true, 14 | 15 | // Vue event method, $emit or $broadcast 16 | notifier: null, 17 | 18 | defaultRoute: '/', 19 | 20 | // Reference to $root.$options.routes 21 | routes: {}, 22 | 23 | // Options to be passed to the routing library 24 | options: { 25 | base: '/', 26 | hashbang: false, 27 | click: true 28 | }, 29 | 30 | // Location context 31 | location: { 32 | regexp: null, 33 | path: null, 34 | componentId: null, 35 | params: null 36 | }, 37 | 38 | oldLocation: { 39 | regexp: null, 40 | path: null, 41 | componentId: null, 42 | params: null 43 | } 44 | }, component); 45 | 46 | // Extend the routing-related methods 47 | _.extend(routeDefinition, routing); 48 | 49 | // override some of components methods 50 | _.extend(routeDefinition, overrides); 51 | 52 | Vue.directive('route', routeDefinition); 53 | }; 54 | -------------------------------------------------------------------------------- /src/overrides.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Overrides for (some of) v-component methods 5 | */ 6 | 7 | var utils = require('./utils'); 8 | 9 | module.exports = function(Vue) { 10 | var component = Vue.directive('_component'), 11 | _ = Vue.util, 12 | parsers = Vue.parsers; 13 | 14 | return { 15 | bind: function() { 16 | // Force dynamic directive 17 | this._isDynamicLiteral = true; 18 | component.bind.call(this); 19 | this.init(); 20 | }, 21 | 22 | /* 23 | This one is copied/pasted from the source 24 | except the routeParams part (no way to override it cleanly :/) 25 | */ 26 | build: function(data) { 27 | var routeData = this.routes[this.location.regexp].data; 28 | 29 | // The 'data' function should use the passed one, if any, 30 | // and get merged with any data passed to the plugin for this route, 31 | // as well as the router params (GET params) 32 | var compData = _.extend({}, data); 33 | compData = _.extend(compData, (utils.isFunction(routeData) ? routeData() : routeData) || {}); 34 | compData = _.extend(compData, { 35 | $routeParams: this.location.params 36 | }); 37 | 38 | if(this.keepAlive) { 39 | var cached = this.cache[this.componentID]; 40 | if(cached) { 41 | _.extend(cached.$data, compData); 42 | return cached; 43 | } 44 | } 45 | 46 | if(this.Component) { 47 | var parent = this._host || this.vm; 48 | var el = parsers.template.clone(this.el); 49 | var child = parent.$addChild({ 50 | el: el, 51 | data: function() { 52 | return compData; 53 | }, 54 | template: this.template, 55 | // if no inline-template, then the compiled 56 | // linker can be cached for better performance. 57 | _linkerCachable: !this.template, 58 | _asComponent: true, 59 | _isRouterView: this._isRouterView, 60 | _context: this.vm 61 | }, this.Component); 62 | 63 | if(this.keepAlive) { 64 | this.cache[this.componentID] = child; 65 | } 66 | 67 | return child; 68 | } 69 | } 70 | }; 71 | }; 72 | -------------------------------------------------------------------------------- /src/routing.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | Routing API 5 | Methods for handling the route change 6 | and trigger the directive update 7 | */ 8 | 9 | module.exports = function(Vue, page, utils) { 10 | var _ = Vue.util; 11 | 12 | /* 13 | Allow to manually navigate to a path. 14 | Useful if you passed the `click: false` option. 15 | */ 16 | Vue.navigate = function(path, trigger) { 17 | page.show(path, null, trigger !== false); 18 | }; 19 | 20 | return { 21 | init: function() { 22 | /* 23 | Link the routes declaration 24 | */ 25 | this.routes = this.vm.$root.$options.routes; 26 | if(!this.routes) { 27 | _.warn('v-route needs the $root to be passed a "routes" option hash.'); 28 | } 29 | 30 | /* 31 | Options for v-route & page (base, hashbang, debug...) 32 | */ 33 | this.options = this.routes.options || {}; 34 | 35 | /* 36 | Use page.base to set the URL base 37 | TODO tests 38 | */ 39 | if(this.options.base) { 40 | page.base(this.options.base); 41 | } 42 | 43 | /* 44 | If options.broadcast, uses $broadcast for routing events, else uses $emit 45 | */ 46 | this.notifier = !!this.options.broadcast ? '$broadcast' : '$emit'; 47 | 48 | /* 49 | Register all the routes 50 | */ 51 | for(var route in this.routes) { 52 | // Ignore options 53 | if(route[0] === '/') { 54 | if(utils.hasOwnProp.call(this.routes, route)) { 55 | this.addRoute(route, this.routes[route]); 56 | } 57 | } 58 | } 59 | 60 | /* 61 | Bind default route 62 | */ 63 | page('*', _.bind(this.onDefaultRoute, this)); 64 | 65 | /* 66 | Start the routing 67 | */ 68 | this.start(); 69 | }, 70 | 71 | /* 72 | Registers the route with the specified path/pattern (express-like regexp) 73 | route: infos as {id: "route-id", path: "/route"} or {id: "route-id", path: "/route/:id"} 74 | */ 75 | addRoute: function(path, options) { 76 | if(this.options.debug) _.log('[v-route] addRoute', path, options); 77 | 78 | var routeFn = function(context, next) { 79 | // Vue.nextTick(function() { 80 | this.onRoute(path, context, next); 81 | // }, this); 82 | }; 83 | 84 | // Add a relevant stack trace 85 | routeFn.displayName = 'routing ' + path; 86 | 87 | // Middleware prop 88 | /* 89 | page(path, onRoute, beforeUpdate, updateRoute, afterUpdate); 90 | - onRoute -> updateLocation field 91 | - beforeUpdate -> emit event, call callbacks, if no callbacks -> next 92 | - updateRoute -> effectively applies the route, next 93 | - afterUpdate -> emit event, call callbacks 94 | */ 95 | 96 | // page(path, _.bind(routeFn, this)); 97 | 98 | page(path, _.bind(routeFn, this), _.bind(this.beforeUpdate, this), _.bind(this.updateRoute, this)); 99 | 100 | if(options.isDefault) { 101 | this.defaultRoute = path; 102 | } 103 | }, 104 | 105 | /* 106 | Starts the router. 107 | */ 108 | start: function() { 109 | if(this.options.debug) _.log('[v-route] start'); 110 | page.start(this.options); 111 | this.vm.$root[this.notifier]('router:started'); 112 | }, 113 | 114 | /* 115 | Internal method. 116 | Updates the context and emit the `router:update` event. 117 | */ 118 | onRoute: function(path, context, next) { 119 | if(this.options.debug) _.log('[v-route] onRoute', path, context); 120 | 121 | /* 122 | Get new route, componentId and update location context 123 | */ 124 | var route = this.routes[path], 125 | componentId = route.componentId; 126 | 127 | this.oldLocation = _.extend({}, this.location); 128 | this.location = { 129 | regexp: path, 130 | path: context.path, 131 | componentId: componentId, 132 | params: context.params 133 | }; 134 | 135 | next(); 136 | }, 137 | 138 | beforeUpdate: function(context, next) { 139 | this.callRouteHook('before', next); 140 | }, 141 | 142 | updateRoute: function() { 143 | /* 144 | Update the current component 145 | */ 146 | var componentId = this.routes[this.location.regexp].componentId; 147 | this.update(componentId); 148 | 149 | /* 150 | after applying the route, emit the event + execute custom callback 151 | */ 152 | this.callRouteHook('after'); 153 | }, 154 | 155 | /* 156 | Called when the requested route does not exists 157 | Redirects to proper default route 158 | */ 159 | onDefaultRoute: function(context) { 160 | if(this.options.debug) _.log('[v-route] onDefaultRoute', context); 161 | 162 | Vue.nextTick(function() { 163 | page(this.defaultRoute); 164 | }, this); 165 | }, 166 | 167 | callRouteHook: function(when, next) { 168 | if(this.options.debug) _.log('[v-route] callRouteHook', when, next); 169 | 170 | var route = this.routes[this.location.regexp], 171 | callback = route[when + 'Update'], 172 | $root = this.vm.$root, 173 | locations = [this.location, this.oldLocation], 174 | middleware; 175 | 176 | if(callback) { 177 | if(utils.isFunction(callback)) { 178 | middleware = callback; 179 | } 180 | else if(utils.isString(callback)) { 181 | if($root[callback]) { 182 | middleware = $root[callback]; 183 | } 184 | } 185 | } 186 | 187 | _.nextTick(function() { 188 | this.callRouteEvents(when, locations); 189 | }, this); 190 | 191 | /* 192 | If a middleware is declared, we call it and wait for the call to `next` 193 | */ 194 | if(middleware) { 195 | middleware.apply($root, utils.concat.call(locations, next)); 196 | } 197 | 198 | /* 199 | If no middleware is declared, we call `next` to continue the routing 200 | */ 201 | else if(next) { 202 | next(); 203 | } 204 | }, 205 | 206 | callRouteEvents: function(when, locations) { 207 | var $root = this.vm.$root; 208 | 209 | $root[this.notifier].apply($root, 210 | utils.concat.call([], 'router:' + when + 'Update', locations) 211 | ); 212 | } 213 | }; 214 | }; 215 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | hasOwnProp: Object.prototype.hasOwnProperty, 5 | toString: Object.prototype.toString, 6 | concat: Array.prototype.concat, 7 | isString: function(str) { 8 | return this.toString.call(str).toLowerCase() == "[object string]"; 9 | }, 10 | isFunction: function(fn) { 11 | return this.toString.call(fn).toLowerCase() == "[object function]"; 12 | } 13 | }; -------------------------------------------------------------------------------- /test/common.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | General purpose tests 5 | */ 6 | 7 | var test = require('prova'), 8 | Vue = require('vue'), 9 | page = require('page'), 10 | route = require('../src/index.js'); 11 | 12 | var has = Object.prototype.hasOwnProperty; 13 | 14 | // Insert pushtate markup 15 | var tempDiv = document.createElement('div'); 16 | tempDiv.innerHTML = ''; 17 | var $head = document.getElementsByTagName('head')[0]; 18 | $head.appendChild(tempDiv.firstChild); 19 | $head.appendChild(tempDiv.firstChild); 20 | // Insert v-route directive 21 | tempDiv.innerHTML = '
'; 22 | document.body.appendChild(tempDiv.firstChild); 23 | 24 | /* 25 | Test setup 26 | */ 27 | Vue.use(route); 28 | 29 | Vue.component('page-1', { 30 | template: '
' 31 | }); 32 | 33 | Vue.component('page-2', { 34 | template: '

' 35 | }); 36 | 37 | Vue.component('page-3', { 38 | template: '
', 39 | created: function() { 40 | this.$root.$emit('page3', this.$data.$routeParams); 41 | } 42 | }); 43 | 44 | var beforeCalled = false, 45 | afterCalled = false, 46 | routes = { 47 | '/page1': { 48 | componentId: 'page-1', 49 | isDefault: true 50 | }, 51 | '/page2': { 52 | componentId: 'page-2', 53 | beforeUpdate: before, 54 | afterUpdate: 'after' 55 | }, 56 | '/page3/:foo': { 57 | componentId: 'page-3' 58 | }, 59 | '/with-data': { 60 | componentId: 'page-1', 61 | data: { 62 | bar: 'baz' 63 | } 64 | }, 65 | options: { 66 | hashbang: true, 67 | base: '/lol', 68 | click: false, 69 | debug: true 70 | } 71 | }; 72 | 73 | function before(location, oldLocation, next) { 74 | beforeCalled = true; 75 | next(); 76 | } 77 | 78 | var root = window.root = new Vue({ 79 | el: 'body', 80 | 81 | routes: routes, 82 | 83 | methods: { 84 | after: function() { 85 | afterCalled = true; 86 | } 87 | } 88 | }); 89 | 90 | test('addRoute', function(assert) { 91 | for(var route in routes) { 92 | if(has.call(routes, route)) { 93 | assert.equal(routes[route], root.$options.routes[route], 'route ' + route + ' should be set.'); 94 | } 95 | } 96 | 97 | assert.end(); 98 | }); 99 | 100 | test('before/after callbacks', function(assert) { 101 | assert.plan(2); 102 | 103 | beforeCalled = false; 104 | afterCalled = false; 105 | 106 | Vue.navigate('/page2'); 107 | 108 | Vue.nextTick(function() { 109 | assert.ok(beforeCalled, 'before callback was called as a method.'); 110 | assert.ok(afterCalled, 'after callback was called as a string (method on root vm).'); 111 | }); 112 | }); 113 | 114 | test('router events', function(assert) { 115 | assert.plan(2); 116 | 117 | root.$on('router:beforeUpdate', function() { 118 | assert.pass('router:beforeUpdate event has been called.'); 119 | }); 120 | 121 | root.$on('router:afterUpdate', function() { 122 | assert.pass('router:afterUpdate event has been called.'); 123 | }); 124 | 125 | Vue.navigate('/page1'); 126 | }); 127 | 128 | 129 | test('location context update', function(assert) { 130 | assert.plan(1); 131 | root.$off(); 132 | 133 | root.$on('router:afterUpdate', function(location, oldLocation) { 134 | assert.notEqual(location.path, oldLocation.path, 'location and oldLocation should be different.'); 135 | }); 136 | 137 | Vue.navigate('/page2'); 138 | }); 139 | 140 | test('route params', function(assert) { 141 | assert.plan(1); 142 | root.$off(); 143 | 144 | var foo = 'thing'; 145 | 146 | root.$on('page3', function(params) { 147 | assert.equal(params.foo, foo, 'The route parameter should have been set.'); 148 | }); 149 | 150 | Vue.navigate('/page3/' + foo); 151 | }); 152 | 153 | test('hashbang', function(assert) { 154 | assert.plan(1); 155 | 156 | assert.equal('#!', window.location.hash.slice(0, 2), 'The URL has an hashbang'); 157 | }); 158 | 159 | test('onDefaultRoute', function(assert) { 160 | assert.plan(1); 161 | 162 | // Navigate to random URL 163 | Vue.navigate('/' + (Math.random() * 10000).toString(36)); 164 | 165 | Vue.nextTick(function() { 166 | assert.equal(location.hash.replace('#!', ''), '/page1', 'Should get back to the default route.'); 167 | }); 168 | }); 169 | 170 | test('data', function(assert) { 171 | assert.plan(1); 172 | root.$off(); 173 | 174 | Vue.navigate('/with-data'); 175 | Vue.nextTick(function() { 176 | assert.equal(root.$children[0].bar, 'baz', 'Should have a data'); 177 | }); 178 | }); 179 | -------------------------------------------------------------------------------- /test/keep-alive-data.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('prova'), 4 | Vue = require('vue'), 5 | page = require('page'), 6 | route = require('../src/index.js'); 7 | 8 | var tempDiv = document.createElement('div'); 9 | tempDiv.innerHTML = '
'; 10 | document.body.appendChild(tempDiv.firstChild); 11 | 12 | var routes = { 13 | '/page1': { 14 | componentId: 'page-1', 15 | data: { 16 | isPage1: true 17 | }, 18 | isDefault: true 19 | }, 20 | '/page2/:page': { 21 | componentId: 'page-2', 22 | data: { 23 | isPage1: 'nope', 24 | isPage2: true 25 | } 26 | } 27 | }; 28 | 29 | Vue.use(route); 30 | 31 | Vue.component('page-1', { 32 | template: '
', 33 | ready: function() { 34 | // console.log('page-1', this.$data.$routeParams.page); 35 | // console.log('page-1', routes['/page2/:page'].data, this.$data); 36 | } 37 | }); 38 | 39 | Vue.component('page-2', { 40 | template: '

', 41 | attached: function() { 42 | // console.log('page-2', this.$data.$routeParams.page); 43 | // console.log('page-2', routes['/page2/:page'].data, this.$data); 44 | } 45 | }); 46 | 47 | /*var root = new Vue({ 48 | el: 'body', 49 | routes: routes 50 | }); 51 | 52 | test('data', function(assert) { 53 | setTimeout(function() { 54 | Vue.navigate('/page2/test'); 55 | setTimeout(function() { 56 | Vue.navigate('/page1'); 57 | setTimeout(function() { 58 | Vue.navigate('/page2/otherParam'); 59 | setTimeout(function() { 60 | Vue.navigate('/page1'); 61 | setTimeout(function() { 62 | Vue.navigate('/page2/andAnother'); 63 | }, 800); 64 | }, 800); 65 | }, 800); 66 | }, 800); 67 | }, 800); 68 | }); 69 | */ 70 | --------------------------------------------------------------------------------