Vue--vue-Router

一.vue路由的基本使用

为什么需要路由?

因为我们通过component切换组件无法给组件传递参数

component切换组件

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4 <meta charset="UTF-8">
 5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7 <title>Document</title>   
 8 <script src="../vue2.4.4.js"></script>
 9 </head>
10 
11 <body>
12 <!-- 定义一个vue的管理区块,(MVVM中的View) -->
13 <template id="account">
14     <div>
15         <a href="#" @click="componentId='login'">登录</a>
16         <a href="#" @click="componentId='register'">注册</a>
17         <!-- :is 相当于给component绑定组件,绑定is后面的值对应的组件 -->
18         <component :is="componentId"></component>
19 </div>
20 </template>
21 <div id="app">
22     <account></account>
23 </div>
24 </body>
25 <script>
26     Vue.component("account",{
27         template:"#account",
28         // 在父组件中添加一个componentId的属性,将来给上面模板中的component使用
29         data:function() {
30             return {
31                 componentId:"login"
32             }
33         },
34         // methods:{
35         //     register:function() {
36         //         this.componentId = "register";
37         //     }
38         // },
39         components:{
40             "login":{
41                 template:"<span>login</span>"
42             },
43             "register":{
44                 template:"<span>register</span>"
45             }
46         }
47     });
48     // 实例化vue对象(MVVM中的View Model)
49     new Vue({
50         // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析
51         el:'#app',
52         data:{
53         // 数据 (MVVM中的Model)   
54         },
55         methods:{
56         }
57     })
58 </script>
59 </html>
View Code

 

使用vue路由需要vue-router.js

   1 /**
   2   * vue-router v3.0.1
   3   * (c) 2017 Evan You
   4   * @license MIT
   5   */
   6   (function (global, factory) {
   7     typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
   8     typeof define === 'function' && define.amd ? define(factory) :
   9     (global.VueRouter = factory());
  10 }(this, (function () { 'use strict';
  11 
  12 /*  */
  13 
  14 function assert (condition, message) {
  15   if (!condition) {
  16     throw new Error(("[vue-router] " + message))
  17   }
  18 }
  19 
  20 function warn (condition, message) {
  21   if ("development" !== 'production' && !condition) {
  22     typeof console !== 'undefined' && console.warn(("[vue-router] " + message));
  23   }
  24 }
  25 
  26 function isError (err) {
  27   return Object.prototype.toString.call(err).indexOf('Error') > -1
  28 }
  29 
  30 var View = {
  31   name: 'router-view',
  32   functional: true,
  33   props: {
  34     name: {
  35       type: String,
  36       default: 'default'
  37     }
  38   },
  39   render: function render (_, ref) {
  40     var props = ref.props;
  41     var children = ref.children;
  42     var parent = ref.parent;
  43     var data = ref.data;
  44 
  45     data.routerView = true;
  46 
  47     // directly use parent context's createElement() function
  48     // so that components rendered by router-view can resolve named slots
  49     var h = parent.$createElement;
  50     var name = props.name;
  51     var route = parent.$route;
  52     var cache = parent._routerViewCache || (parent._routerViewCache = {});
  53 
  54     // determine current view depth, also check to see if the tree
  55     // has been toggled inactive but kept-alive.
  56     var depth = 0;
  57     var inactive = false;
  58     while (parent && parent._routerRoot !== parent) {
  59       if (parent.$vnode && parent.$vnode.data.routerView) {
  60         depth++;
  61       }
  62       if (parent._inactive) {
  63         inactive = true;
  64       }
  65       parent = parent.$parent;
  66     }
  67     data.routerViewDepth = depth;
  68 
  69     // render previous view if the tree is inactive and kept-alive
  70     if (inactive) {
  71       return h(cache[name], data, children)
  72     }
  73 
  74     var matched = route.matched[depth];
  75     // render empty node if no matched route
  76     if (!matched) {
  77       cache[name] = null;
  78       return h()
  79     }
  80 
  81     var component = cache[name] = matched.components[name];
  82 
  83     // attach instance registration hook
  84     // this will be called in the instance's injected lifecycle hooks
  85     data.registerRouteInstance = function (vm, val) {
  86       // val could be undefined for unregistration
  87       var current = matched.instances[name];
  88       if (
  89         (val && current !== vm) ||
  90         (!val && current === vm)
  91       ) {
  92         matched.instances[name] = val;
  93       }
  94     }
  95 
  96     // also register instance in prepatch hook
  97     // in case the same component instance is reused across different routes
  98     ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {
  99       matched.instances[name] = vnode.componentInstance;
 100     };
 101 
 102     // resolve props
 103     var propsToPass = data.props = resolveProps(route, matched.props && matched.props[name]);
 104     if (propsToPass) {
 105       // clone to prevent mutation
 106       propsToPass = data.props = extend({}, propsToPass);
 107       // pass non-declared props as attrs
 108       var attrs = data.attrs = data.attrs || {};
 109       for (var key in propsToPass) {
 110         if (!component.props || !(key in component.props)) {
 111           attrs[key] = propsToPass[key];
 112           delete propsToPass[key];
 113         }
 114       }
 115     }
 116 
 117     return h(component, data, children)
 118   }
 119 };
 120 
 121 function resolveProps (route, config) {
 122   switch (typeof config) {
 123     case 'undefined':
 124       return
 125     case 'object':
 126       return config
 127     case 'function':
 128       return config(route)
 129     case 'boolean':
 130       return config ? route.params : undefined
 131     default:
 132       {
 133         warn(
 134           false,
 135           "props in \"" + (route.path) + "\" is a " + (typeof config) + ", " +
 136           "expecting an object, function or boolean."
 137         );
 138       }
 139   }
 140 }
 141 
 142 function extend (to, from) {
 143   for (var key in from) {
 144     to[key] = from[key];
 145   }
 146   return to
 147 }
 148 
 149 /*  */
 150 
 151 var encodeReserveRE = /[!'()*]/g;
 152 var encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };
 153 var commaRE = /%2C/g;
 154 
 155 // fixed encodeURIComponent which is more conformant to RFC3986:
 156 // - escapes [!'()*]
 157 // - preserve commas
 158 var encode = function (str) { return encodeURIComponent(str)
 159   .replace(encodeReserveRE, encodeReserveReplacer)
 160   .replace(commaRE, ','); };
 161 
 162 var decode = decodeURIComponent;
 163 
 164 function resolveQuery (
 165   query,
 166   extraQuery,
 167   _parseQuery
 168 ) {
 169   if ( extraQuery === void 0 ) extraQuery = {};
 170 
 171   var parse = _parseQuery || parseQuery;
 172   var parsedQuery;
 173   try {
 174     parsedQuery = parse(query || '');
 175   } catch (e) {
 176     "development" !== 'production' && warn(false, e.message);
 177     parsedQuery = {};
 178   }
 179   for (var key in extraQuery) {
 180     parsedQuery[key] = extraQuery[key];
 181   }
 182   return parsedQuery
 183 }
 184 
 185 function parseQuery (query) {
 186   var res = {};
 187 
 188   query = query.trim().replace(/^(\?|#|&)/, '');
 189 
 190   if (!query) {
 191     return res
 192   }
 193 
 194   query.split('&').forEach(function (param) {
 195     var parts = param.replace(/\+/g, ' ').split('=');
 196     var key = decode(parts.shift());
 197     var val = parts.length > 0
 198       ? decode(parts.join('='))
 199       : null;
 200 
 201     if (res[key] === undefined) {
 202       res[key] = val;
 203     } else if (Array.isArray(res[key])) {
 204       res[key].push(val);
 205     } else {
 206       res[key] = [res[key], val];
 207     }
 208   });
 209 
 210   return res
 211 }
 212 
 213 function stringifyQuery (obj) {
 214   var res = obj ? Object.keys(obj).map(function (key) {
 215     var val = obj[key];
 216 
 217     if (val === undefined) {
 218       return ''
 219     }
 220 
 221     if (val === null) {
 222       return encode(key)
 223     }
 224 
 225     if (Array.isArray(val)) {
 226       var result = [];
 227       val.forEach(function (val2) {
 228         if (val2 === undefined) {
 229           return
 230         }
 231         if (val2 === null) {
 232           result.push(encode(key));
 233         } else {
 234           result.push(encode(key) + '=' + encode(val2));
 235         }
 236       });
 237       return result.join('&')
 238     }
 239 
 240     return encode(key) + '=' + encode(val)
 241   }).filter(function (x) { return x.length > 0; }).join('&') : null;
 242   return res ? ("?" + res) : ''
 243 }
 244 
 245 /*  */
 246 
 247 
 248 var trailingSlashRE = /\/?$/;
 249 
 250 function createRoute (
 251   record,
 252   location,
 253   redirectedFrom,
 254   router
 255 ) {
 256   var stringifyQuery$$1 = router && router.options.stringifyQuery;
 257 
 258   var query = location.query || {};
 259   try {
 260     query = clone(query);
 261   } catch (e) {}
 262 
 263   var route = {
 264     name: location.name || (record && record.name),
 265     meta: (record && record.meta) || {},
 266     path: location.path || '/',
 267     hash: location.hash || '',
 268     query: query,
 269     params: location.params || {},
 270     fullPath: getFullPath(location, stringifyQuery$$1),
 271     matched: record ? formatMatch(record) : []
 272   };
 273   if (redirectedFrom) {
 274     route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery$$1);
 275   }
 276   return Object.freeze(route)
 277 }
 278 
 279 function clone (value) {
 280   if (Array.isArray(value)) {
 281     return value.map(clone)
 282   } else if (value && typeof value === 'object') {
 283     var res = {};
 284     for (var key in value) {
 285       res[key] = clone(value[key]);
 286     }
 287     return res
 288   } else {
 289     return value
 290   }
 291 }
 292 
 293 // the starting route that represents the initial state
 294 var START = createRoute(null, {
 295   path: '/'
 296 });
 297 
 298 function formatMatch (record) {
 299   var res = [];
 300   while (record) {
 301     res.unshift(record);
 302     record = record.parent;
 303   }
 304   return res
 305 }
 306 
 307 function getFullPath (
 308   ref,
 309   _stringifyQuery
 310 ) {
 311   var path = ref.path;
 312   var query = ref.query; if ( query === void 0 ) query = {};
 313   var hash = ref.hash; if ( hash === void 0 ) hash = '';
 314 
 315   var stringify = _stringifyQuery || stringifyQuery;
 316   return (path || '/') + stringify(query) + hash
 317 }
 318 
 319 function isSameRoute (a, b) {
 320   if (b === START) {
 321     return a === b
 322   } else if (!b) {
 323     return false
 324   } else if (a.path && b.path) {
 325     return (
 326       a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
 327       a.hash === b.hash &&
 328       isObjectEqual(a.query, b.query)
 329     )
 330   } else if (a.name && b.name) {
 331     return (
 332       a.name === b.name &&
 333       a.hash === b.hash &&
 334       isObjectEqual(a.query, b.query) &&
 335       isObjectEqual(a.params, b.params)
 336     )
 337   } else {
 338     return false
 339   }
 340 }
 341 
 342 function isObjectEqual (a, b) {
 343   if ( a === void 0 ) a = {};
 344   if ( b === void 0 ) b = {};
 345 
 346   // handle null value #1566
 347   if (!a || !b) { return a === b }
 348   var aKeys = Object.keys(a);
 349   var bKeys = Object.keys(b);
 350   if (aKeys.length !== bKeys.length) {
 351     return false
 352   }
 353   return aKeys.every(function (key) {
 354     var aVal = a[key];
 355     var bVal = b[key];
 356     // check nested equality
 357     if (typeof aVal === 'object' && typeof bVal === 'object') {
 358       return isObjectEqual(aVal, bVal)
 359     }
 360     return String(aVal) === String(bVal)
 361   })
 362 }
 363 
 364 function isIncludedRoute (current, target) {
 365   return (
 366     current.path.replace(trailingSlashRE, '/').indexOf(
 367       target.path.replace(trailingSlashRE, '/')
 368     ) === 0 &&
 369     (!target.hash || current.hash === target.hash) &&
 370     queryIncludes(current.query, target.query)
 371   )
 372 }
 373 
 374 function queryIncludes (current, target) {
 375   for (var key in target) {
 376     if (!(key in current)) {
 377       return false
 378     }
 379   }
 380   return true
 381 }
 382 
 383 /*  */
 384 
 385 // work around weird flow bug
 386 var toTypes = [String, Object];
 387 var eventTypes = [String, Array];
 388 
 389 var Link = {
 390   name: 'router-link',
 391   props: {
 392     to: {
 393       type: toTypes,
 394       required: true
 395     },
 396     tag: {
 397       type: String,
 398       default: 'a'
 399     },
 400     exact: Boolean,
 401     append: Boolean,
 402     replace: Boolean,
 403     activeClass: String,
 404     exactActiveClass: String,
 405     event: {
 406       type: eventTypes,
 407       default: 'click'
 408     }
 409   },
 410   render: function render (h) {
 411     var this$1 = this;
 412 
 413     var router = this.$router;
 414     var current = this.$route;
 415     var ref = router.resolve(this.to, current, this.append);
 416     var location = ref.location;
 417     var route = ref.route;
 418     var href = ref.href;
 419 
 420     var classes = {};
 421     var globalActiveClass = router.options.linkActiveClass;
 422     var globalExactActiveClass = router.options.linkExactActiveClass;
 423     // Support global empty active class
 424     var activeClassFallback = globalActiveClass == null
 425             ? 'router-link-active'
 426             : globalActiveClass;
 427     var exactActiveClassFallback = globalExactActiveClass == null
 428             ? 'router-link-exact-active'
 429             : globalExactActiveClass;
 430     var activeClass = this.activeClass == null
 431             ? activeClassFallback
 432             : this.activeClass;
 433     var exactActiveClass = this.exactActiveClass == null
 434             ? exactActiveClassFallback
 435             : this.exactActiveClass;
 436     var compareTarget = location.path
 437       ? createRoute(null, location, null, router)
 438       : route;
 439 
 440     classes[exactActiveClass] = isSameRoute(current, compareTarget);
 441     classes[activeClass] = this.exact
 442       ? classes[exactActiveClass]
 443       : isIncludedRoute(current, compareTarget);
 444 
 445     var handler = function (e) {
 446       if (guardEvent(e)) {
 447         if (this$1.replace) {
 448           router.replace(location);
 449         } else {
 450           router.push(location);
 451         }
 452       }
 453     };
 454 
 455     var on = { click: guardEvent };
 456     if (Array.isArray(this.event)) {
 457       this.event.forEach(function (e) { on[e] = handler; });
 458     } else {
 459       on[this.event] = handler;
 460     }
 461 
 462     var data = {
 463       class: classes
 464     };
 465 
 466     if (this.tag === 'a') {
 467       data.on = on;
 468       data.attrs = { href: href };
 469     } else {
 470       // find the first <a> child and apply listener and href
 471       var a = findAnchor(this.$slots.default);
 472       if (a) {
 473         // in case the <a> is a static node
 474         a.isStatic = false;
 475         var extend = _Vue.util.extend;
 476         var aData = a.data = extend({}, a.data);
 477         aData.on = on;
 478         var aAttrs = a.data.attrs = extend({}, a.data.attrs);
 479         aAttrs.href = href;
 480       } else {
 481         // doesn't have <a> child, apply listener to self
 482         data.on = on;
 483       }
 484     }
 485 
 486     return h(this.tag, data, this.$slots.default)
 487   }
 488 };
 489 
 490 function guardEvent (e) {
 491   // don't redirect with control keys
 492   if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
 493   // don't redirect when preventDefault called
 494   if (e.defaultPrevented) { return }
 495   // don't redirect on right click
 496   if (e.button !== undefined && e.button !== 0) { return }
 497   // don't redirect if `target="_blank"`
 498   if (e.currentTarget && e.currentTarget.getAttribute) {
 499     var target = e.currentTarget.getAttribute('target');
 500     if (/\b_blank\b/i.test(target)) { return }
 501   }
 502   // this may be a Weex event which doesn't have this method
 503   if (e.preventDefault) {
 504     e.preventDefault();
 505   }
 506   return true
 507 }
 508 
 509 function findAnchor (children) {
 510   if (children) {
 511     var child;
 512     for (var i = 0; i < children.length; i++) {
 513       child = children[i];
 514       if (child.tag === 'a') {
 515         return child
 516       }
 517       if (child.children && (child = findAnchor(child.children))) {
 518         return child
 519       }
 520     }
 521   }
 522 }
 523 
 524 var _Vue;
 525 
 526 function install (Vue) {
 527   if (install.installed && _Vue === Vue) { return }
 528   install.installed = true;
 529 
 530   _Vue = Vue;
 531 
 532   var isDef = function (v) { return v !== undefined; };
 533 
 534   var registerInstance = function (vm, callVal) {
 535     var i = vm.$options._parentVnode;
 536     if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
 537       i(vm, callVal);
 538     }
 539   };
 540 
 541   Vue.mixin({
 542     beforeCreate: function beforeCreate () {
 543       if (isDef(this.$options.router)) {
 544         this._routerRoot = this;
 545         this._router = this.$options.router;
 546         this._router.init(this);
 547         Vue.util.defineReactive(this, '_route', this._router.history.current);
 548       } else {
 549         this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
 550       }
 551       registerInstance(this, this);
 552     },
 553     destroyed: function destroyed () {
 554       registerInstance(this);
 555     }
 556   });
 557 
 558   Object.defineProperty(Vue.prototype, '$router', {
 559     get: function get () { return this._routerRoot._router }
 560   });
 561 
 562   Object.defineProperty(Vue.prototype, '$route', {
 563     get: function get () { return this._routerRoot._route }
 564   });
 565 
 566   Vue.component('router-view', View);
 567   Vue.component('router-link', Link);
 568 
 569   var strats = Vue.config.optionMergeStrategies;
 570   // use the same hook merging strategy for route hooks
 571   strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;
 572 }
 573 
 574 /*  */
 575 
 576 var inBrowser = typeof window !== 'undefined';
 577 
 578 /*  */
 579 
 580 function resolvePath (
 581   relative,
 582   base,
 583   append
 584 ) {
 585   var firstChar = relative.charAt(0);
 586   if (firstChar === '/') {
 587     return relative
 588   }
 589 
 590   if (firstChar === '?' || firstChar === '#') {
 591     return base + relative
 592   }
 593 
 594   var stack = base.split('/');
 595 
 596   // remove trailing segment if:
 597   // - not appending
 598   // - appending to trailing slash (last segment is empty)
 599   if (!append || !stack[stack.length - 1]) {
 600     stack.pop();
 601   }
 602 
 603   // resolve relative path
 604   var segments = relative.replace(/^\//, '').split('/');
 605   for (var i = 0; i < segments.length; i++) {
 606     var segment = segments[i];
 607     if (segment === '..') {
 608       stack.pop();
 609     } else if (segment !== '.') {
 610       stack.push(segment);
 611     }
 612   }
 613 
 614   // ensure leading slash
 615   if (stack[0] !== '') {
 616     stack.unshift('');
 617   }
 618 
 619   return stack.join('/')
 620 }
 621 
 622 function parsePath (path) {
 623   var hash = '';
 624   var query = '';
 625 
 626   var hashIndex = path.indexOf('#');
 627   if (hashIndex >= 0) {
 628     hash = path.slice(hashIndex);
 629     path = path.slice(0, hashIndex);
 630   }
 631 
 632   var queryIndex = path.indexOf('?');
 633   if (queryIndex >= 0) {
 634     query = path.slice(queryIndex + 1);
 635     path = path.slice(0, queryIndex);
 636   }
 637 
 638   return {
 639     path: path,
 640     query: query,
 641     hash: hash
 642   }
 643 }
 644 
 645 function cleanPath (path) {
 646   return path.replace(/\/\//g, '/')
 647 }
 648 
 649 var isarray = Array.isArray || function (arr) {
 650   return Object.prototype.toString.call(arr) == '[object Array]';
 651 };
 652 
 653 /**
 654  * Expose `pathToRegexp`.
 655  */
 656 var pathToRegexp_1 = pathToRegexp;
 657 var parse_1 = parse;
 658 var compile_1 = compile;
 659 var tokensToFunction_1 = tokensToFunction;
 660 var tokensToRegExp_1 = tokensToRegExp;
 661 
 662 /**
 663  * The main path matching regexp utility.
 664  *
 665  * @type {RegExp}
 666  */
 667 var PATH_REGEXP = new RegExp([
 668   // Match escaped characters that would otherwise appear in future matches.
 669   // This allows the user to escape special characters that won't transform.
 670   '(\\\\.)',
 671   // Match Express-style parameters and un-named parameters with a prefix
 672   // and optional suffixes. Matches appear as:
 673   //
 674   // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
 675   // "/route(\\d+)"  => [undefined, undefined, undefined, "\d+", undefined, undefined]
 676   // "/*"            => ["/", undefined, undefined, undefined, undefined, "*"]
 677   '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
 678 ].join('|'), 'g');
 679 
 680 /**
 681  * Parse a string for the raw tokens.
 682  *
 683  * @param  {string}  str
 684  * @param  {Object=} options
 685  * @return {!Array}
 686  */
 687 function parse (str, options) {
 688   var tokens = [];
 689   var key = 0;
 690   var index = 0;
 691   var path = '';
 692   var defaultDelimiter = options && options.delimiter || '/';
 693   var res;
 694 
 695   while ((res = PATH_REGEXP.exec(str)) != null) {
 696     var m = res[0];
 697     var escaped = res[1];
 698     var offset = res.index;
 699     path += str.slice(index, offset);
 700     index = offset + m.length;
 701 
 702     // Ignore already escaped sequences.
 703     if (escaped) {
 704       path += escaped[1];
 705       continue
 706     }
 707 
 708     var next = str[index];
 709     var prefix = res[2];
 710     var name = res[3];
 711     var capture = res[4];
 712     var group = res[5];
 713     var modifier = res[6];
 714     var asterisk = res[7];
 715 
 716     // Push the current path onto the tokens.
 717     if (path) {
 718       tokens.push(path);
 719       path = '';
 720     }
 721 
 722     var partial = prefix != null && next != null && next !== prefix;
 723     var repeat = modifier === '+' || modifier === '*';
 724     var optional = modifier === '?' || modifier === '*';
 725     var delimiter = res[2] || defaultDelimiter;
 726     var pattern = capture || group;
 727 
 728     tokens.push({
 729       name: name || key++,
 730       prefix: prefix || '',
 731       delimiter: delimiter,
 732       optional: optional,
 733       repeat: repeat,
 734       partial: partial,
 735       asterisk: !!asterisk,
 736       pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
 737     });
 738   }
 739 
 740   // Match any characters still remaining.
 741   if (index < str.length) {
 742     path += str.substr(index);
 743   }
 744 
 745   // If the path exists, push it onto the end.
 746   if (path) {
 747     tokens.push(path);
 748   }
 749 
 750   return tokens
 751 }
 752 
 753 /**
 754  * Compile a string to a template function for the path.
 755  *
 756  * @param  {string}             str
 757  * @param  {Object=}            options
 758  * @return {!function(Object=, Object=)}
 759  */
 760 function compile (str, options) {
 761   return tokensToFunction(parse(str, options))
 762 }
 763 
 764 /**
 765  * Prettier encoding of URI path segments.
 766  *
 767  * @param  {string}
 768  * @return {string}
 769  */
 770 function encodeURIComponentPretty (str) {
 771   return encodeURI(str).replace(/[\/?#]/g, function (c) {
 772     return '%' + c.charCodeAt(0).toString(16).toUpperCase()
 773   })
 774 }
 775 
 776 /**
 777  * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
 778  *
 779  * @param  {string}
 780  * @return {string}
 781  */
 782 function encodeAsterisk (str) {
 783   return encodeURI(str).replace(/[?#]/g, function (c) {
 784     return '%' + c.charCodeAt(0).toString(16).toUpperCase()
 785   })
 786 }
 787 
 788 /**
 789  * Expose a method for transforming tokens into the path function.
 790  */
 791 function tokensToFunction (tokens) {
 792   // Compile all the tokens into regexps.
 793   var matches = new Array(tokens.length);
 794 
 795   // Compile all the patterns before compilation.
 796   for (var i = 0; i < tokens.length; i++) {
 797     if (typeof tokens[i] === 'object') {
 798       matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
 799     }
 800   }
 801 
 802   return function (obj, opts) {
 803     var path = '';
 804     var data = obj || {};
 805     var options = opts || {};
 806     var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
 807 
 808     for (var i = 0; i < tokens.length; i++) {
 809       var token = tokens[i];
 810 
 811       if (typeof token === 'string') {
 812         path += token;
 813 
 814         continue
 815       }
 816 
 817       var value = data[token.name];
 818       var segment;
 819 
 820       if (value == null) {
 821         if (token.optional) {
 822           // Prepend partial segment prefixes.
 823           if (token.partial) {
 824             path += token.prefix;
 825           }
 826 
 827           continue
 828         } else {
 829           throw new TypeError('Expected "' + token.name + '" to be defined')
 830         }
 831       }
 832 
 833       if (isarray(value)) {
 834         if (!token.repeat) {
 835           throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
 836         }
 837 
 838         if (value.length === 0) {
 839           if (token.optional) {
 840             continue
 841           } else {
 842             throw new TypeError('Expected "' + token.name + '" to not be empty')
 843           }
 844         }
 845 
 846         for (var j = 0; j < value.length; j++) {
 847           segment = encode(value[j]);
 848 
 849           if (!matches[i].test(segment)) {
 850             throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
 851           }
 852 
 853           path += (j === 0 ? token.prefix : token.delimiter) + segment;
 854         }
 855 
 856         continue
 857       }
 858 
 859       segment = token.asterisk ? encodeAsterisk(value) : encode(value);
 860 
 861       if (!matches[i].test(segment)) {
 862         throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
 863       }
 864 
 865       path += token.prefix + segment;
 866     }
 867 
 868     return path
 869   }
 870 }
 871 
 872 /**
 873  * Escape a regular expression string.
 874  *
 875  * @param  {string} str
 876  * @return {string}
 877  */
 878 function escapeString (str) {
 879   return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
 880 }
 881 
 882 /**
 883  * Escape the capturing group by escaping special characters and meaning.
 884  *
 885  * @param  {string} group
 886  * @return {string}
 887  */
 888 function escapeGroup (group) {
 889   return group.replace(/([=!:$\/()])/g, '\\$1')
 890 }
 891 
 892 /**
 893  * Attach the keys as a property of the regexp.
 894  *
 895  * @param  {!RegExp} re
 896  * @param  {Array}   keys
 897  * @return {!RegExp}
 898  */
 899 function attachKeys (re, keys) {
 900   re.keys = keys;
 901   return re
 902 }
 903 
 904 /**
 905  * Get the flags for a regexp from the options.
 906  *
 907  * @param  {Object} options
 908  * @return {string}
 909  */
 910 function flags (options) {
 911   return options.sensitive ? '' : 'i'
 912 }
 913 
 914 /**
 915  * Pull out keys from a regexp.
 916  *
 917  * @param  {!RegExp} path
 918  * @param  {!Array}  keys
 919  * @return {!RegExp}
 920  */
 921 function regexpToRegexp (path, keys) {
 922   // Use a negative lookahead to match only capturing groups.
 923   var groups = path.source.match(/\((?!\?)/g);
 924 
 925   if (groups) {
 926     for (var i = 0; i < groups.length; i++) {
 927       keys.push({
 928         name: i,
 929         prefix: null,
 930         delimiter: null,
 931         optional: false,
 932         repeat: false,
 933         partial: false,
 934         asterisk: false,
 935         pattern: null
 936       });
 937     }
 938   }
 939 
 940   return attachKeys(path, keys)
 941 }
 942 
 943 /**
 944  * Transform an array into a regexp.
 945  *
 946  * @param  {!Array}  path
 947  * @param  {Array}   keys
 948  * @param  {!Object} options
 949  * @return {!RegExp}
 950  */
 951 function arrayToRegexp (path, keys, options) {
 952   var parts = [];
 953 
 954   for (var i = 0; i < path.length; i++) {
 955     parts.push(pathToRegexp(path[i], keys, options).source);
 956   }
 957 
 958   var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
 959 
 960   return attachKeys(regexp, keys)
 961 }
 962 
 963 /**
 964  * Create a path regexp from string input.
 965  *
 966  * @param  {string}  path
 967  * @param  {!Array}  keys
 968  * @param  {!Object} options
 969  * @return {!RegExp}
 970  */
 971 function stringToRegexp (path, keys, options) {
 972   return tokensToRegExp(parse(path, options), keys, options)
 973 }
 974 
 975 /**
 976  * Expose a function for taking tokens and returning a RegExp.
 977  *
 978  * @param  {!Array}          tokens
 979  * @param  {(Array|Object)=} keys
 980  * @param  {Object=}         options
 981  * @return {!RegExp}
 982  */
 983 function tokensToRegExp (tokens, keys, options) {
 984   if (!isarray(keys)) {
 985     options = /** @type {!Object} */ (keys || options);
 986     keys = [];
 987   }
 988 
 989   options = options || {};
 990 
 991   var strict = options.strict;
 992   var end = options.end !== false;
 993   var route = '';
 994 
 995   // Iterate over the tokens and create our regexp string.
 996   for (var i = 0; i < tokens.length; i++) {
 997     var token = tokens[i];
 998 
 999     if (typeof token === 'string') {
1000       route += escapeString(token);
1001     } else {
1002       var prefix = escapeString(token.prefix);
1003       var capture = '(?:' + token.pattern + ')';
1004 
1005       keys.push(token);
1006 
1007       if (token.repeat) {
1008         capture += '(?:' + prefix + capture + ')*';
1009       }
1010 
1011       if (token.optional) {
1012         if (!token.partial) {
1013           capture = '(?:' + prefix + '(' + capture + '))?';
1014         } else {
1015           capture = prefix + '(' + capture + ')?';
1016         }
1017       } else {
1018         capture = prefix + '(' + capture + ')';
1019       }
1020 
1021       route += capture;
1022     }
1023   }
1024 
1025   var delimiter = escapeString(options.delimiter || '/');
1026   var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
1027 
1028   // In non-strict mode we allow a slash at the end of match. If the path to
1029   // match already ends with a slash, we remove it for consistency. The slash
1030   // is valid at the end of a path match, not in the middle. This is important
1031   // in non-ending mode, where "/test/" shouldn't match "/test//route".
1032   if (!strict) {
1033     route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
1034   }
1035 
1036   if (end) {
1037     route += '$';
1038   } else {
1039     // In non-ending mode, we need the capturing groups to match as much as
1040     // possible by using a positive lookahead to the end or next path segment.
1041     route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
1042   }
1043 
1044   return attachKeys(new RegExp('^' + route, flags(options)), keys)
1045 }
1046 
1047 /**
1048  * Normalize the given path string, returning a regular expression.
1049  *
1050  * An empty array can be passed in for the keys, which will hold the
1051  * placeholder key descriptions. For example, using `/user/:id`, `keys` will
1052  * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
1053  *
1054  * @param  {(string|RegExp|Array)} path
1055  * @param  {(Array|Object)=}       keys
1056  * @param  {Object=}               options
1057  * @return {!RegExp}
1058  */
1059 function pathToRegexp (path, keys, options) {
1060   if (!isarray(keys)) {
1061     options = /** @type {!Object} */ (keys || options);
1062     keys = [];
1063   }
1064 
1065   options = options || {};
1066 
1067   if (path instanceof RegExp) {
1068     return regexpToRegexp(path, /** @type {!Array} */ (keys))
1069   }
1070 
1071   if (isarray(path)) {
1072     return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
1073   }
1074 
1075   return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
1076 }
1077 
1078 pathToRegexp_1.parse = parse_1;
1079 pathToRegexp_1.compile = compile_1;
1080 pathToRegexp_1.tokensToFunction = tokensToFunction_1;
1081 pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
1082 
1083 /*  */
1084 
1085 // $flow-disable-line
1086 var regexpCompileCache = Object.create(null);
1087 
1088 function fillParams (
1089   path,
1090   params,
1091   routeMsg
1092 ) {
1093   try {
1094     var filler =
1095       regexpCompileCache[path] ||
1096       (regexpCompileCache[path] = pathToRegexp_1.compile(path));
1097     return filler(params || {}, { pretty: true })
1098   } catch (e) {
1099     {
1100       warn(false, ("missing param for " + routeMsg + ": " + (e.message)));
1101     }
1102     return ''
1103   }
1104 }
1105 
1106 /*  */
1107 
1108 function createRouteMap (
1109   routes,
1110   oldPathList,
1111   oldPathMap,
1112   oldNameMap
1113 ) {
1114   // the path list is used to control path matching priority
1115   var pathList = oldPathList || [];
1116   // $flow-disable-line
1117   var pathMap = oldPathMap || Object.create(null);
1118   // $flow-disable-line
1119   var nameMap = oldNameMap || Object.create(null);
1120 
1121   routes.forEach(function (route) {
1122     addRouteRecord(pathList, pathMap, nameMap, route);
1123   });
1124 
1125   // ensure wildcard routes are always at the end
1126   for (var i = 0, l = pathList.length; i < l; i++) {
1127     if (pathList[i] === '*') {
1128       pathList.push(pathList.splice(i, 1)[0]);
1129       l--;
1130       i--;
1131     }
1132   }
1133 
1134   return {
1135     pathList: pathList,
1136     pathMap: pathMap,
1137     nameMap: nameMap
1138   }
1139 }
1140 
1141 function addRouteRecord (
1142   pathList,
1143   pathMap,
1144   nameMap,
1145   route,
1146   parent,
1147   matchAs
1148 ) {
1149   var path = route.path;
1150   var name = route.name;
1151   {
1152     assert(path != null, "\"path\" is required in a route configuration.");
1153     assert(
1154       typeof route.component !== 'string',
1155       "route config \"component\" for path: " + (String(path || name)) + " cannot be a " +
1156       "string id. Use an actual component instead."
1157     );
1158   }
1159 
1160   var pathToRegexpOptions = route.pathToRegexpOptions || {};
1161   var normalizedPath = normalizePath(
1162     path,
1163     parent,
1164     pathToRegexpOptions.strict
1165   );
1166 
1167   if (typeof route.caseSensitive === 'boolean') {
1168     pathToRegexpOptions.sensitive = route.caseSensitive;
1169   }
1170 
1171   var record = {
1172     path: normalizedPath,
1173     regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
1174     components: route.components || { default: route.component },
1175     instances: {},
1176     name: name,
1177     parent: parent,
1178     matchAs: matchAs,
1179     redirect: route.redirect,
1180     beforeEnter: route.beforeEnter,
1181     meta: route.meta || {},
1182     props: route.props == null
1183       ? {}
1184       : route.components
1185         ? route.props
1186         : { default: route.props }
1187   };
1188 
1189   if (route.children) {
1190     // Warn if route is named, does not redirect and has a default child route.
1191     // If users navigate to this route by name, the default child will
1192     // not be rendered (GH Issue #629)
1193     {
1194       if (route.name && !route.redirect && route.children.some(function (child) { return /^\/?$/.test(child.path); })) {
1195         warn(
1196           false,
1197           "Named Route '" + (route.name) + "' has a default child route. " +
1198           "When navigating to this named route (:to=\"{name: '" + (route.name) + "'\"), " +
1199           "the default child route will not be rendered. Remove the name from " +
1200           "this route and use the name of the default child route for named " +
1201           "links instead."
1202         );
1203       }
1204     }
1205     route.children.forEach(function (child) {
1206       var childMatchAs = matchAs
1207         ? cleanPath((matchAs + "/" + (child.path)))
1208         : undefined;
1209       addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);
1210     });
1211   }
1212 
1213   if (route.alias !== undefined) {
1214     var aliases = Array.isArray(route.alias)
1215       ? route.alias
1216       : [route.alias];
1217 
1218     aliases.forEach(function (alias) {
1219       var aliasRoute = {
1220         path: alias,
1221         children: route.children
1222       };
1223       addRouteRecord(
1224         pathList,
1225         pathMap,
1226         nameMap,
1227         aliasRoute,
1228         parent,
1229         record.path || '/' // matchAs
1230       );
1231     });
1232   }
1233 
1234   if (!pathMap[record.path]) {
1235     pathList.push(record.path);
1236     pathMap[record.path] = record;
1237   }
1238 
1239   if (name) {
1240     if (!nameMap[name]) {
1241       nameMap[name] = record;
1242     } else if ("development" !== 'production' && !matchAs) {
1243       warn(
1244         false,
1245         "Duplicate named routes definition: " +
1246         "{ name: \"" + name + "\", path: \"" + (record.path) + "\" }"
1247       );
1248     }
1249   }
1250 }
1251 
1252 function compileRouteRegex (path, pathToRegexpOptions) {
1253   var regex = pathToRegexp_1(path, [], pathToRegexpOptions);
1254   {
1255     var keys = Object.create(null);
1256     regex.keys.forEach(function (key) {
1257       warn(!keys[key.name], ("Duplicate param keys in route with path: \"" + path + "\""));
1258       keys[key.name] = true;
1259     });
1260   }
1261   return regex
1262 }
1263 
1264 function normalizePath (path, parent, strict) {
1265   if (!strict) { path = path.replace(/\/$/, ''); }
1266   if (path[0] === '/') { return path }
1267   if (parent == null) { return path }
1268   return cleanPath(((parent.path) + "/" + path))
1269 }
1270 
1271 /*  */
1272 
1273 
1274 function normalizeLocation (
1275   raw,
1276   current,
1277   append,
1278   router
1279 ) {
1280   var next = typeof raw === 'string' ? { path: raw } : raw;
1281   // named target
1282   if (next.name || next._normalized) {
1283     return next
1284   }
1285 
1286   // relative params
1287   if (!next.path && next.params && current) {
1288     next = assign({}, next);
1289     next._normalized = true;
1290     var params = assign(assign({}, current.params), next.params);
1291     if (current.name) {
1292       next.name = current.name;
1293       next.params = params;
1294     } else if (current.matched.length) {
1295       var rawPath = current.matched[current.matched.length - 1].path;
1296       next.path = fillParams(rawPath, params, ("path " + (current.path)));
1297     } else {
1298       warn(false, "relative params navigation requires a current route.");
1299     }
1300     return next
1301   }
1302 
1303   var parsedPath = parsePath(next.path || '');
1304   var basePath = (current && current.path) || '/';
1305   var path = parsedPath.path
1306     ? resolvePath(parsedPath.path, basePath, append || next.append)
1307     : basePath;
1308 
1309   var query = resolveQuery(
1310     parsedPath.query,
1311     next.query,
1312     router && router.options.parseQuery
1313   );
1314 
1315   var hash = next.hash || parsedPath.hash;
1316   if (hash && hash.charAt(0) !== '#') {
1317     hash = "#" + hash;
1318   }
1319 
1320   return {
1321     _normalized: true,
1322     path: path,
1323     query: query,
1324     hash: hash
1325   }
1326 }
1327 
1328 function assign (a, b) {
1329   for (var key in b) {
1330     a[key] = b[key];
1331   }
1332   return a
1333 }
1334 
1335 /*  */
1336 
1337 
1338 function createMatcher (
1339   routes,
1340   router
1341 ) {
1342   var ref = createRouteMap(routes);
1343   var pathList = ref.pathList;
1344   var pathMap = ref.pathMap;
1345   var nameMap = ref.nameMap;
1346 
1347   function addRoutes (routes) {
1348     createRouteMap(routes, pathList, pathMap, nameMap);
1349   }
1350 
1351   function match (
1352     raw,
1353     currentRoute,
1354     redirectedFrom
1355   ) {
1356     var location = normalizeLocation(raw, currentRoute, false, router);
1357     var name = location.name;
1358 
1359     if (name) {
1360       var record = nameMap[name];
1361       {
1362         warn(record, ("Route with name '" + name + "' does not exist"));
1363       }
1364       if (!record) { return _createRoute(null, location) }
1365       var paramNames = record.regex.keys
1366         .filter(function (key) { return !key.optional; })
1367         .map(function (key) { return key.name; });
1368 
1369       if (typeof location.params !== 'object') {
1370         location.params = {};
1371       }
1372 
1373       if (currentRoute && typeof currentRoute.params === 'object') {
1374         for (var key in currentRoute.params) {
1375           if (!(key in location.params) && paramNames.indexOf(key) > -1) {
1376             location.params[key] = currentRoute.params[key];
1377           }
1378         }
1379       }
1380 
1381       if (record) {
1382         location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""));
1383         return _createRoute(record, location, redirectedFrom)
1384       }
1385     } else if (location.path) {
1386       location.params = {};
1387       for (var i = 0; i < pathList.length; i++) {
1388         var path = pathList[i];
1389         var record$1 = pathMap[path];
1390         if (matchRoute(record$1.regex, location.path, location.params)) {
1391           return _createRoute(record$1, location, redirectedFrom)
1392         }
1393       }
1394     }
1395     // no match
1396     return _createRoute(null, location)
1397   }
1398 
1399   function redirect (
1400     record,
1401     location
1402   ) {
1403     var originalRedirect = record.redirect;
1404     var redirect = typeof originalRedirect === 'function'
1405         ? originalRedirect(createRoute(record, location, null, router))
1406         : originalRedirect;
1407 
1408     if (typeof redirect === 'string') {
1409       redirect = { path: redirect };
1410     }
1411 
1412     if (!redirect || typeof redirect !== 'object') {
1413       {
1414         warn(
1415           false, ("invalid redirect option: " + (JSON.stringify(redirect)))
1416         );
1417       }
1418       return _createRoute(null, location)
1419     }
1420 
1421     var re = redirect;
1422     var name = re.name;
1423     var path = re.path;
1424     var query = location.query;
1425     var hash = location.hash;
1426     var params = location.params;
1427     query = re.hasOwnProperty('query') ? re.query : query;
1428     hash = re.hasOwnProperty('hash') ? re.hash : hash;
1429     params = re.hasOwnProperty('params') ? re.params : params;
1430 
1431     if (name) {
1432       // resolved named direct
1433       var targetRecord = nameMap[name];
1434       {
1435         assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."));
1436       }
1437       return match({
1438         _normalized: true,
1439         name: name,
1440         query: query,
1441         hash: hash,
1442         params: params
1443       }, undefined, location)
1444     } else if (path) {
1445       // 1. resolve relative redirect
1446       var rawPath = resolveRecordPath(path, record);
1447       // 2. resolve params
1448       var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""));
1449       // 3. rematch with existing query and hash
1450       return match({
1451         _normalized: true,
1452         path: resolvedPath,
1453         query: query,
1454         hash: hash
1455       }, undefined, location)
1456     } else {
1457       {
1458         warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))));
1459       }
1460       return _createRoute(null, location)
1461     }
1462   }
1463 
1464   function alias (
1465     record,
1466     location,
1467     matchAs
1468   ) {
1469     var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""));
1470     var aliasedMatch = match({
1471       _normalized: true,
1472       path: aliasedPath
1473     });
1474     if (aliasedMatch) {
1475       var matched = aliasedMatch.matched;
1476       var aliasedRecord = matched[matched.length - 1];
1477       location.params = aliasedMatch.params;
1478       return _createRoute(aliasedRecord, location)
1479     }
1480     return _createRoute(null, location)
1481   }
1482 
1483   function _createRoute (
1484     record,
1485     location,
1486     redirectedFrom
1487   ) {
1488     if (record && record.redirect) {
1489       return redirect(record, redirectedFrom || location)
1490     }
1491     if (record && record.matchAs) {
1492       return alias(record, location, record.matchAs)
1493     }
1494     return createRoute(record, location, redirectedFrom, router)
1495   }
1496 
1497   return {
1498     match: match,
1499     addRoutes: addRoutes
1500   }
1501 }
1502 
1503 function matchRoute (
1504   regex,
1505   path,
1506   params
1507 ) {
1508   var m = path.match(regex);
1509 
1510   if (!m) {
1511     return false
1512   } else if (!params) {
1513     return true
1514   }
1515 
1516   for (var i = 1, len = m.length; i < len; ++i) {
1517     var key = regex.keys[i - 1];
1518     var val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];
1519     if (key) {
1520       params[key.name] = val;
1521     }
1522   }
1523 
1524   return true
1525 }
1526 
1527 function resolveRecordPath (path, record) {
1528   return resolvePath(path, record.parent ? record.parent.path : '/', true)
1529 }
1530 
1531 /*  */
1532 
1533 
1534 var positionStore = Object.create(null);
1535 
1536 function setupScroll () {
1537   // Fix for #1585 for Firefox
1538   window.history.replaceState({ key: getStateKey() }, '');
1539   window.addEventListener('popstate', function (e) {
1540     saveScrollPosition();
1541     if (e.state && e.state.key) {
1542       setStateKey(e.state.key);
1543     }
1544   });
1545 }
1546 
1547 function handleScroll (
1548   router,
1549   to,
1550   from,
1551   isPop
1552 ) {
1553   if (!router.app) {
1554     return
1555   }
1556 
1557   var behavior = router.options.scrollBehavior;
1558   if (!behavior) {
1559     return
1560   }
1561 
1562   {
1563     assert(typeof behavior === 'function', "scrollBehavior must be a function");
1564   }
1565 
1566   // wait until re-render finishes before scrolling
1567   router.app.$nextTick(function () {
1568     var position = getScrollPosition();
1569     var shouldScroll = behavior(to, from, isPop ? position : null);
1570 
1571     if (!shouldScroll) {
1572       return
1573     }
1574 
1575     if (typeof shouldScroll.then === 'function') {
1576       shouldScroll.then(function (shouldScroll) {
1577         scrollToPosition((shouldScroll), position);
1578       }).catch(function (err) {
1579         {
1580           assert(false, err.toString());
1581         }
1582       });
1583     } else {
1584       scrollToPosition(shouldScroll, position);
1585     }
1586   });
1587 }
1588 
1589 function saveScrollPosition () {
1590   var key = getStateKey();
1591   if (key) {
1592     positionStore[key] = {
1593       x: window.pageXOffset,
1594       y: window.pageYOffset
1595     };
1596   }
1597 }
1598 
1599 function getScrollPosition () {
1600   var key = getStateKey();
1601   if (key) {
1602     return positionStore[key]
1603   }
1604 }
1605 
1606 function getElementPosition (el, offset) {
1607   var docEl = document.documentElement;
1608   var docRect = docEl.getBoundingClientRect();
1609   var elRect = el.getBoundingClientRect();
1610   return {
1611     x: elRect.left - docRect.left - offset.x,
1612     y: elRect.top - docRect.top - offset.y
1613   }
1614 }
1615 
1616 function isValidPosition (obj) {
1617   return isNumber(obj.x) || isNumber(obj.y)
1618 }
1619 
1620 function normalizePosition (obj) {
1621   return {
1622     x: isNumber(obj.x) ? obj.x : window.pageXOffset,
1623     y: isNumber(obj.y) ? obj.y : window.pageYOffset
1624   }
1625 }
1626 
1627 function normalizeOffset (obj) {
1628   return {
1629     x: isNumber(obj.x) ? obj.x : 0,
1630     y: isNumber(obj.y) ? obj.y : 0
1631   }
1632 }
1633 
1634 function isNumber (v) {
1635   return typeof v === 'number'
1636 }
1637 
1638 function scrollToPosition (shouldScroll, position) {
1639   var isObject = typeof shouldScroll === 'object';
1640   if (isObject && typeof shouldScroll.selector === 'string') {
1641     var el = document.querySelector(shouldScroll.selector);
1642     if (el) {
1643       var offset = shouldScroll.offset && typeof shouldScroll.offset === 'object' ? shouldScroll.offset : {};
1644       offset = normalizeOffset(offset);
1645       position = getElementPosition(el, offset);
1646     } else if (isValidPosition(shouldScroll)) {
1647       position = normalizePosition(shouldScroll);
1648     }
1649   } else if (isObject && isValidPosition(shouldScroll)) {
1650     position = normalizePosition(shouldScroll);
1651   }
1652 
1653   if (position) {
1654     window.scrollTo(position.x, position.y);
1655   }
1656 }
1657 
1658 /*  */
1659 
1660 var supportsPushState = inBrowser && (function () {
1661   var ua = window.navigator.userAgent;
1662 
1663   if (
1664     (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
1665     ua.indexOf('Mobile Safari') !== -1 &&
1666     ua.indexOf('Chrome') === -1 &&
1667     ua.indexOf('Windows Phone') === -1
1668   ) {
1669     return false
1670   }
1671 
1672   return window.history && 'pushState' in window.history
1673 })();
1674 
1675 // use User Timing api (if present) for more accurate key precision
1676 var Time = inBrowser && window.performance && window.performance.now
1677   ? window.performance
1678   : Date;
1679 
1680 var _key = genKey();
1681 
1682 function genKey () {
1683   return Time.now().toFixed(3)
1684 }
1685 
1686 function getStateKey () {
1687   return _key
1688 }
1689 
1690 function setStateKey (key) {
1691   _key = key;
1692 }
1693 
1694 function pushState (url, replace) {
1695   saveScrollPosition();
1696   // try...catch the pushState call to get around Safari
1697   // DOM Exception 18 where it limits to 100 pushState calls
1698   var history = window.history;
1699   try {
1700     if (replace) {
1701       history.replaceState({ key: _key }, '', url);
1702     } else {
1703       _key = genKey();
1704       history.pushState({ key: _key }, '', url);
1705     }
1706   } catch (e) {
1707     window.location[replace ? 'replace' : 'assign'](url);
1708   }
1709 }
1710 
1711 function replaceState (url) {
1712   pushState(url, true);
1713 }
1714 
1715 /*  */
1716 
1717 function runQueue (queue, fn, cb) {
1718   var step = function (index) {
1719     if (index >= queue.length) {
1720       cb();
1721     } else {
1722       if (queue[index]) {
1723         fn(queue[index], function () {
1724           step(index + 1);
1725         });
1726       } else {
1727         step(index + 1);
1728       }
1729     }
1730   };
1731   step(0);
1732 }
1733 
1734 /*  */
1735 
1736 function resolveAsyncComponents (matched) {
1737   return function (to, from, next) {
1738     var hasAsync = false;
1739     var pending = 0;
1740     var error = null;
1741 
1742     flatMapComponents(matched, function (def, _, match, key) {
1743       // if it's a function and doesn't have cid attached,
1744       // assume it's an async component resolve function.
1745       // we are not using Vue's default async resolving mechanism because
1746       // we want to halt the navigation until the incoming component has been
1747       // resolved.
1748       if (typeof def === 'function' && def.cid === undefined) {
1749         hasAsync = true;
1750         pending++;
1751 
1752         var resolve = once(function (resolvedDef) {
1753           if (isESModule(resolvedDef)) {
1754             resolvedDef = resolvedDef.default;
1755           }
1756           // save resolved on async factory in case it's used elsewhere
1757           def.resolved = typeof resolvedDef === 'function'
1758             ? resolvedDef
1759             : _Vue.extend(resolvedDef);
1760           match.components[key] = resolvedDef;
1761           pending--;
1762           if (pending <= 0) {
1763             next();
1764           }
1765         });
1766 
1767         var reject = once(function (reason) {
1768           var msg = "Failed to resolve async component " + key + ": " + reason;
1769           "development" !== 'production' && warn(false, msg);
1770           if (!error) {
1771             error = isError(reason)
1772               ? reason
1773               : new Error(msg);
1774             next(error);
1775           }
1776         });
1777 
1778         var res;
1779         try {
1780           res = def(resolve, reject);
1781         } catch (e) {
1782           reject(e);
1783         }
1784         if (res) {
1785           if (typeof res.then === 'function') {
1786             res.then(resolve, reject);
1787           } else {
1788             // new syntax in Vue 2.3
1789             var comp = res.component;
1790             if (comp && typeof comp.then === 'function') {
1791               comp.then(resolve, reject);
1792             }
1793           }
1794         }
1795       }
1796     });
1797 
1798     if (!hasAsync) { next(); }
1799   }
1800 }
1801 
1802 function flatMapComponents (
1803   matched,
1804   fn
1805 ) {
1806   return flatten(matched.map(function (m) {
1807     return Object.keys(m.components).map(function (key) { return fn(
1808       m.components[key],
1809       m.instances[key],
1810       m, key
1811     ); })
1812   }))
1813 }
1814 
1815 function flatten (arr) {
1816   return Array.prototype.concat.apply([], arr)
1817 }
1818 
1819 var hasSymbol =
1820   typeof Symbol === 'function' &&
1821   typeof Symbol.toStringTag === 'symbol';
1822 
1823 function isESModule (obj) {
1824   return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
1825 }
1826 
1827 // in Webpack 2, require.ensure now also returns a Promise
1828 // so the resolve/reject functions may get called an extra time
1829 // if the user uses an arrow function shorthand that happens to
1830 // return that Promise.
1831 function once (fn) {
1832   var called = false;
1833   return function () {
1834     var args = [], len = arguments.length;
1835     while ( len-- ) args[ len ] = arguments[ len ];
1836 
1837     if (called) { return }
1838     called = true;
1839     return fn.apply(this, args)
1840   }
1841 }
1842 
1843 /*  */
1844 
1845 var History = function History (router, base) {
1846   this.router = router;
1847   this.base = normalizeBase(base);
1848   // start with a route object that stands for "nowhere"
1849   this.current = START;
1850   this.pending = null;
1851   this.ready = false;
1852   this.readyCbs = [];
1853   this.readyErrorCbs = [];
1854   this.errorCbs = [];
1855 };
1856 
1857 History.prototype.listen = function listen (cb) {
1858   this.cb = cb;
1859 };
1860 
1861 History.prototype.onReady = function onReady (cb, errorCb) {
1862   if (this.ready) {
1863     cb();
1864   } else {
1865     this.readyCbs.push(cb);
1866     if (errorCb) {
1867       this.readyErrorCbs.push(errorCb);
1868     }
1869   }
1870 };
1871 
1872 History.prototype.onError = function onError (errorCb) {
1873   this.errorCbs.push(errorCb);
1874 };
1875 
1876 History.prototype.transitionTo = function transitionTo (location, onComplete, onAbort) {
1877     var this$1 = this;
1878 
1879   var route = this.router.match(location, this.current);
1880   this.confirmTransition(route, function () {
1881     this$1.updateRoute(route);
1882     onComplete && onComplete(route);
1883     this$1.ensureURL();
1884 
1885     // fire ready cbs once
1886     if (!this$1.ready) {
1887       this$1.ready = true;
1888       this$1.readyCbs.forEach(function (cb) { cb(route); });
1889     }
1890   }, function (err) {
1891     if (onAbort) {
1892       onAbort(err);
1893     }
1894     if (err && !this$1.ready) {
1895       this$1.ready = true;
1896       this$1.readyErrorCbs.forEach(function (cb) { cb(err); });
1897     }
1898   });
1899 };
1900 
1901 History.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {
1902     var this$1 = this;
1903 
1904   var current = this.current;
1905   var abort = function (err) {
1906     if (isError(err)) {
1907       if (this$1.errorCbs.length) {
1908         this$1.errorCbs.forEach(function (cb) { cb(err); });
1909       } else {
1910         warn(false, 'uncaught error during route navigation:');
1911         console.error(err);
1912       }
1913     }
1914     onAbort && onAbort(err);
1915   };
1916   if (
1917     isSameRoute(route, current) &&
1918     // in the case the route map has been dynamically appended to
1919     route.matched.length === current.matched.length
1920   ) {
1921     this.ensureURL();
1922     return abort()
1923   }
1924 
1925   var ref = resolveQueue(this.current.matched, route.matched);
1926     var updated = ref.updated;
1927     var deactivated = ref.deactivated;
1928     var activated = ref.activated;
1929 
1930   var queue = [].concat(
1931     // in-component leave guards
1932     extractLeaveGuards(deactivated),
1933     // global before hooks
1934     this.router.beforeHooks,
1935     // in-component update hooks
1936     extractUpdateHooks(updated),
1937     // in-config enter guards
1938     activated.map(function (m) { return m.beforeEnter; }),
1939     // async components
1940     resolveAsyncComponents(activated)
1941   );
1942 
1943   this.pending = route;
1944   var iterator = function (hook, next) {
1945     if (this$1.pending !== route) {
1946       return abort()
1947     }
1948     try {
1949       hook(route, current, function (to) {
1950         if (to === false || isError(to)) {
1951           // next(false) -> abort navigation, ensure current URL
1952           this$1.ensureURL(true);
1953           abort(to);
1954         } else if (
1955           typeof to === 'string' ||
1956           (typeof to === 'object' && (
1957             typeof to.path === 'string' ||
1958             typeof to.name === 'string'
1959           ))
1960         ) {
1961           // next('/') or next({ path: '/' }) -> redirect
1962           abort();
1963           if (typeof to === 'object' && to.replace) {
1964             this$1.replace(to);
1965           } else {
1966             this$1.push(to);
1967           }
1968         } else {
1969           // confirm transition and pass on the value
1970           next(to);
1971         }
1972       });
1973     } catch (e) {
1974       abort(e);
1975     }
1976   };
1977 
1978   runQueue(queue, iterator, function () {
1979     var postEnterCbs = [];
1980     var isValid = function () { return this$1.current === route; };
1981     // wait until async components are resolved before
1982     // extracting in-component enter guards
1983     var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
1984     var queue = enterGuards.concat(this$1.router.resolveHooks);
1985     runQueue(queue, iterator, function () {
1986       if (this$1.pending !== route) {
1987         return abort()
1988       }
1989       this$1.pending = null;
1990       onComplete(route);
1991       if (this$1.router.app) {
1992         this$1.router.app.$nextTick(function () {
1993           postEnterCbs.forEach(function (cb) { cb(); });
1994         });
1995       }
1996     });
1997   });
1998 };
1999 
2000 History.prototype.updateRoute = function updateRoute (route) {
2001   var prev = this.current;
2002   this.current = route;
2003   this.cb && this.cb(route);
2004   this.router.afterHooks.forEach(function (hook) {
2005     hook && hook(route, prev);
2006   });
2007 };
2008 
2009 function normalizeBase (base) {
2010   if (!base) {
2011     if (inBrowser) {
2012       // respect <base> tag
2013       var baseEl = document.querySelector('base');
2014       base = (baseEl && baseEl.getAttribute('href')) || '/';
2015       // strip full URL origin
2016       base = base.replace(/^https?:\/\/[^\/]+/, '');
2017     } else {
2018       base = '/';
2019     }
2020   }
2021   // make sure there's the starting slash
2022   if (base.charAt(0) !== '/') {
2023     base = '/' + base;
2024   }
2025   // remove trailing slash
2026   return base.replace(/\/$/, '')
2027 }
2028 
2029 function resolveQueue (
2030   current,
2031   next
2032 ) {
2033   var i;
2034   var max = Math.max(current.length, next.length);
2035   for (i = 0; i < max; i++) {
2036     if (current[i] !== next[i]) {
2037       break
2038     }
2039   }
2040   return {
2041     updated: next.slice(0, i),
2042     activated: next.slice(i),
2043     deactivated: current.slice(i)
2044   }
2045 }
2046 
2047 function extractGuards (
2048   records,
2049   name,
2050   bind,
2051   reverse
2052 ) {
2053   var guards = flatMapComponents(records, function (def, instance, match, key) {
2054     var guard = extractGuard(def, name);
2055     if (guard) {
2056       return Array.isArray(guard)
2057         ? guard.map(function (guard) { return bind(guard, instance, match, key); })
2058         : bind(guard, instance, match, key)
2059     }
2060   });
2061   return flatten(reverse ? guards.reverse() : guards)
2062 }
2063 
2064 function extractGuard (
2065   def,
2066   key
2067 ) {
2068   if (typeof def !== 'function') {
2069     // extend now so that global mixins are applied.
2070     def = _Vue.extend(def);
2071   }
2072   return def.options[key]
2073 }
2074 
2075 function extractLeaveGuards (deactivated) {
2076   return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
2077 }
2078 
2079 function extractUpdateHooks (updated) {
2080   return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
2081 }
2082 
2083 function bindGuard (guard, instance) {
2084   if (instance) {
2085     return function boundRouteGuard () {
2086       return guard.apply(instance, arguments)
2087     }
2088   }
2089 }
2090 
2091 function extractEnterGuards (
2092   activated,
2093   cbs,
2094   isValid
2095 ) {
2096   return extractGuards(activated, 'beforeRouteEnter', function (guard, _, match, key) {
2097     return bindEnterGuard(guard, match, key, cbs, isValid)
2098   })
2099 }
2100 
2101 function bindEnterGuard (
2102   guard,
2103   match,
2104   key,
2105   cbs,
2106   isValid
2107 ) {
2108   return function routeEnterGuard (to, from, next) {
2109     return guard(to, from, function (cb) {
2110       next(cb);
2111       if (typeof cb === 'function') {
2112         cbs.push(function () {
2113           // #750
2114           // if a router-view is wrapped with an out-in transition,
2115           // the instance may not have been registered at this time.
2116           // we will need to poll for registration until current route
2117           // is no longer valid.
2118           poll(cb, match.instances, key, isValid);
2119         });
2120       }
2121     })
2122   }
2123 }
2124 
2125 function poll (
2126   cb, // somehow flow cannot infer this is a function
2127   instances,
2128   key,
2129   isValid
2130 ) {
2131   if (instances[key]) {
2132     cb(instances[key]);
2133   } else if (isValid()) {
2134     setTimeout(function () {
2135       poll(cb, instances, key, isValid);
2136     }, 16);
2137   }
2138 }
2139 
2140 /*  */
2141 
2142 
2143 var HTML5History = (function (History$$1) {
2144   function HTML5History (router, base) {
2145     var this$1 = this;
2146 
2147     History$$1.call(this, router, base);
2148 
2149     var expectScroll = router.options.scrollBehavior;
2150 
2151     if (expectScroll) {
2152       setupScroll();
2153     }
2154 
2155     var initLocation = getLocation(this.base);
2156     window.addEventListener('popstate', function (e) {
2157       var current = this$1.current;
2158 
2159       // Avoiding first `popstate` event dispatched in some browsers but first
2160       // history route not updated since async guard at the same time.
2161       var location = getLocation(this$1.base);
2162       if (this$1.current === START && location === initLocation) {
2163         return
2164       }
2165 
2166       this$1.transitionTo(location, function (route) {
2167         if (expectScroll) {
2168           handleScroll(router, route, current, true);
2169         }
2170       });
2171     });
2172   }
2173 
2174   if ( History$$1 ) HTML5History.__proto__ = History$$1;
2175   HTML5History.prototype = Object.create( History$$1 && History$$1.prototype );
2176   HTML5History.prototype.constructor = HTML5History;
2177 
2178   HTML5History.prototype.go = function go (n) {
2179     window.history.go(n);
2180   };
2181 
2182   HTML5History.prototype.push = function push (location, onComplete, onAbort) {
2183     var this$1 = this;
2184 
2185     var ref = this;
2186     var fromRoute = ref.current;
2187     this.transitionTo(location, function (route) {
2188       pushState(cleanPath(this$1.base + route.fullPath));
2189       handleScroll(this$1.router, route, fromRoute, false);
2190       onComplete && onComplete(route);
2191     }, onAbort);
2192   };
2193 
2194   HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {
2195     var this$1 = this;
2196 
2197     var ref = this;
2198     var fromRoute = ref.current;
2199     this.transitionTo(location, function (route) {
2200       replaceState(cleanPath(this$1.base + route.fullPath));
2201       handleScroll(this$1.router, route, fromRoute, false);
2202       onComplete && onComplete(route);
2203     }, onAbort);
2204   };
2205 
2206   HTML5History.prototype.ensureURL = function ensureURL (push) {
2207     if (getLocation(this.base) !== this.current.fullPath) {
2208       var current = cleanPath(this.base + this.current.fullPath);
2209       push ? pushState(current) : replaceState(current);
2210     }
2211   };
2212 
2213   HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {
2214     return getLocation(this.base)
2215   };
2216 
2217   return HTML5History;
2218 }(History));
2219 
2220 function getLocation (base) {
2221   var path = window.location.pathname;
2222   if (base && path.indexOf(base) === 0) {
2223     path = path.slice(base.length);
2224   }
2225   return (path || '/') + window.location.search + window.location.hash
2226 }
2227 
2228 /*  */
2229 
2230 
2231 var HashHistory = (function (History$$1) {
2232   function HashHistory (router, base, fallback) {
2233     History$$1.call(this, router, base);
2234     // check history fallback deeplinking
2235     if (fallback && checkFallback(this.base)) {
2236       return
2237     }
2238     ensureSlash();
2239   }
2240 
2241   if ( History$$1 ) HashHistory.__proto__ = History$$1;
2242   HashHistory.prototype = Object.create( History$$1 && History$$1.prototype );
2243   HashHistory.prototype.constructor = HashHistory;
2244 
2245   // this is delayed until the app mounts
2246   // to avoid the hashchange listener being fired too early
2247   HashHistory.prototype.setupListeners = function setupListeners () {
2248     var this$1 = this;
2249 
2250     var router = this.router;
2251     var expectScroll = router.options.scrollBehavior;
2252     var supportsScroll = supportsPushState && expectScroll;
2253 
2254     if (supportsScroll) {
2255       setupScroll();
2256     }
2257 
2258     window.addEventListener(supportsPushState ? 'popstate' : 'hashchange', function () {
2259       var current = this$1.current;
2260       if (!ensureSlash()) {
2261         return
2262       }
2263       this$1.transitionTo(getHash(), function (route) {
2264         if (supportsScroll) {
2265           handleScroll(this$1.router, route, current, true);
2266         }
2267         if (!supportsPushState) {
2268           replaceHash(route.fullPath);
2269         }
2270       });
2271     });
2272   };
2273 
2274   HashHistory.prototype.push = function push (location, onComplete, onAbort) {
2275     var this$1 = this;
2276 
2277     var ref = this;
2278     var fromRoute = ref.current;
2279     this.transitionTo(location, function (route) {
2280       pushHash(route.fullPath);
2281       handleScroll(this$1.router, route, fromRoute, false);
2282       onComplete && onComplete(route);
2283     }, onAbort);
2284   };
2285 
2286   HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {
2287     var this$1 = this;
2288 
2289     var ref = this;
2290     var fromRoute = ref.current;
2291     this.transitionTo(location, function (route) {
2292       replaceHash(route.fullPath);
2293       handleScroll(this$1.router, route, fromRoute, false);
2294       onComplete && onComplete(route);
2295     }, onAbort);
2296   };
2297 
2298   HashHistory.prototype.go = function go (n) {
2299     window.history.go(n);
2300   };
2301 
2302   HashHistory.prototype.ensureURL = function ensureURL (push) {
2303     var current = this.current.fullPath;
2304     if (getHash() !== current) {
2305       push ? pushHash(current) : replaceHash(current);
2306     }
2307   };
2308 
2309   HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {
2310     return getHash()
2311   };
2312 
2313   return HashHistory;
2314 }(History));
2315 
2316 function checkFallback (base) {
2317   var location = getLocation(base);
2318   if (!/^\/#/.test(location)) {
2319     window.location.replace(
2320       cleanPath(base + '/#' + location)
2321     );
2322     return true
2323   }
2324 }
2325 
2326 function ensureSlash () {
2327   var path = getHash();
2328   if (path.charAt(0) === '/') {
2329     return true
2330   }
2331   replaceHash('/' + path);
2332   return false
2333 }
2334 
2335 function getHash () {
2336   // We can't use window.location.hash here because it's not
2337   // consistent across browsers - Firefox will pre-decode it!
2338   var href = window.location.href;
2339   var index = href.indexOf('#');
2340   return index === -1 ? '' : href.slice(index + 1)
2341 }
2342 
2343 function getUrl (path) {
2344   var href = window.location.href;
2345   var i = href.indexOf('#');
2346   var base = i >= 0 ? href.slice(0, i) : href;
2347   return (base + "#" + path)
2348 }
2349 
2350 function pushHash (path) {
2351   if (supportsPushState) {
2352     pushState(getUrl(path));
2353   } else {
2354     window.location.hash = path;
2355   }
2356 }
2357 
2358 function replaceHash (path) {
2359   if (supportsPushState) {
2360     replaceState(getUrl(path));
2361   } else {
2362     window.location.replace(getUrl(path));
2363   }
2364 }
2365 
2366 /*  */
2367 
2368 
2369 var AbstractHistory = (function (History$$1) {
2370   function AbstractHistory (router, base) {
2371     History$$1.call(this, router, base);
2372     this.stack = [];
2373     this.index = -1;
2374   }
2375 
2376   if ( History$$1 ) AbstractHistory.__proto__ = History$$1;
2377   AbstractHistory.prototype = Object.create( History$$1 && History$$1.prototype );
2378   AbstractHistory.prototype.constructor = AbstractHistory;
2379 
2380   AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {
2381     var this$1 = this;
2382 
2383     this.transitionTo(location, function (route) {
2384       this$1.stack = this$1.stack.slice(0, this$1.index + 1).concat(route);
2385       this$1.index++;
2386       onComplete && onComplete(route);
2387     }, onAbort);
2388   };
2389 
2390   AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {
2391     var this$1 = this;
2392 
2393     this.transitionTo(location, function (route) {
2394       this$1.stack = this$1.stack.slice(0, this$1.index).concat(route);
2395       onComplete && onComplete(route);
2396     }, onAbort);
2397   };
2398 
2399   AbstractHistory.prototype.go = function go (n) {
2400     var this$1 = this;
2401 
2402     var targetIndex = this.index + n;
2403     if (targetIndex < 0 || targetIndex >= this.stack.length) {
2404       return
2405     }
2406     var route = this.stack[targetIndex];
2407     this.confirmTransition(route, function () {
2408       this$1.index = targetIndex;
2409       this$1.updateRoute(route);
2410     });
2411   };
2412 
2413   AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {
2414     var current = this.stack[this.stack.length - 1];
2415     return current ? current.fullPath : '/'
2416   };
2417 
2418   AbstractHistory.prototype.ensureURL = function ensureURL () {
2419     // noop
2420   };
2421 
2422   return AbstractHistory;
2423 }(History));
2424 
2425 /*  */
2426 
2427 var VueRouter = function VueRouter (options) {
2428   if ( options === void 0 ) options = {};
2429 
2430   this.app = null;
2431   this.apps = [];
2432   this.options = options;
2433   this.beforeHooks = [];
2434   this.resolveHooks = [];
2435   this.afterHooks = [];
2436   this.matcher = createMatcher(options.routes || [], this);
2437 
2438   var mode = options.mode || 'hash';
2439   this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false;
2440   if (this.fallback) {
2441     mode = 'hash';
2442   }
2443   if (!inBrowser) {
2444     mode = 'abstract';
2445   }
2446   this.mode = mode;
2447 
2448   switch (mode) {
2449     case 'history':
2450       this.history = new HTML5History(this, options.base);
2451       break
2452     case 'hash':
2453       this.history = new HashHistory(this, options.base, this.fallback);
2454       break
2455     case 'abstract':
2456       this.history = new AbstractHistory(this, options.base);
2457       break
2458     default:
2459       {
2460         assert(false, ("invalid mode: " + mode));
2461       }
2462   }
2463 };
2464 
2465 var prototypeAccessors = { currentRoute: { configurable: true } };
2466 
2467 VueRouter.prototype.match = function match (
2468   raw,
2469   current,
2470   redirectedFrom
2471 ) {
2472   return this.matcher.match(raw, current, redirectedFrom)
2473 };
2474 
2475 prototypeAccessors.currentRoute.get = function () {
2476   return this.history && this.history.current
2477 };
2478 
2479 VueRouter.prototype.init = function init (app /* Vue component instance */) {
2480     var this$1 = this;
2481 
2482   "development" !== 'production' && assert(
2483     install.installed,
2484     "not installed. Make sure to call `Vue.use(VueRouter)` " +
2485     "before creating root instance."
2486   );
2487 
2488   this.apps.push(app);
2489 
2490   // main app already initialized.
2491   if (this.app) {
2492     return
2493   }
2494 
2495   this.app = app;
2496 
2497   var history = this.history;
2498 
2499   if (history instanceof HTML5History) {
2500     history.transitionTo(history.getCurrentLocation());
2501   } else if (history instanceof HashHistory) {
2502     var setupHashListener = function () {
2503       history.setupListeners();
2504     };
2505     history.transitionTo(
2506       history.getCurrentLocation(),
2507       setupHashListener,
2508       setupHashListener
2509     );
2510   }
2511 
2512   history.listen(function (route) {
2513     this$1.apps.forEach(function (app) {
2514       app._route = route;
2515     });
2516   });
2517 };
2518 
2519 VueRouter.prototype.beforeEach = function beforeEach (fn) {
2520   return registerHook(this.beforeHooks, fn)
2521 };
2522 
2523 VueRouter.prototype.beforeResolve = function beforeResolve (fn) {
2524   return registerHook(this.resolveHooks, fn)
2525 };
2526 
2527 VueRouter.prototype.afterEach = function afterEach (fn) {
2528   return registerHook(this.afterHooks, fn)
2529 };
2530 
2531 VueRouter.prototype.onReady = function onReady (cb, errorCb) {
2532   this.history.onReady(cb, errorCb);
2533 };
2534 
2535 VueRouter.prototype.onError = function onError (errorCb) {
2536   this.history.onError(errorCb);
2537 };
2538 
2539 VueRouter.prototype.push = function push (location, onComplete, onAbort) {
2540   this.history.push(location, onComplete, onAbort);
2541 };
2542 
2543 VueRouter.prototype.replace = function replace (location, onComplete, onAbort) {
2544   this.history.replace(location, onComplete, onAbort);
2545 };
2546 
2547 VueRouter.prototype.go = function go (n) {
2548   this.history.go(n);
2549 };
2550 
2551 VueRouter.prototype.back = function back () {
2552   this.go(-1);
2553 };
2554 
2555 VueRouter.prototype.forward = function forward () {
2556   this.go(1);
2557 };
2558 
2559 VueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {
2560   var route = to
2561     ? to.matched
2562       ? to
2563       : this.resolve(to).route
2564     : this.currentRoute;
2565   if (!route) {
2566     return []
2567   }
2568   return [].concat.apply([], route.matched.map(function (m) {
2569     return Object.keys(m.components).map(function (key) {
2570       return m.components[key]
2571     })
2572   }))
2573 };
2574 
2575 VueRouter.prototype.resolve = function resolve (
2576   to,
2577   current,
2578   append
2579 ) {
2580   var location = normalizeLocation(
2581     to,
2582     current || this.history.current,
2583     append,
2584     this
2585   );
2586   var route = this.match(location, current);
2587   var fullPath = route.redirectedFrom || route.fullPath;
2588   var base = this.history.base;
2589   var href = createHref(base, fullPath, this.mode);
2590   return {
2591     location: location,
2592     route: route,
2593     href: href,
2594     // for backwards compat
2595     normalizedTo: location,
2596     resolved: route
2597   }
2598 };
2599 
2600 VueRouter.prototype.addRoutes = function addRoutes (routes) {
2601   this.matcher.addRoutes(routes);
2602   if (this.history.current !== START) {
2603     this.history.transitionTo(this.history.getCurrentLocation());
2604   }
2605 };
2606 
2607 Object.defineProperties( VueRouter.prototype, prototypeAccessors );
2608 
2609 function registerHook (list, fn) {
2610   list.push(fn);
2611   return function () {
2612     var i = list.indexOf(fn);
2613     if (i > -1) { list.splice(i, 1); }
2614   }
2615 }
2616 
2617 function createHref (base, fullPath, mode) {
2618   var path = mode === 'hash' ? '#' + fullPath : fullPath;
2619   return base ? cleanPath(base + '/' + path) : path
2620 }
2621 
2622 VueRouter.install = install;
2623 VueRouter.version = '3.0.1';
2624 
2625 if (inBrowser && window.Vue) {
2626   window.Vue.use(VueRouter);
2627 }
2628 
2629 return VueRouter;
2630 
2631 })));
View Code
vue-router的使用要分为六步:
  1.引用js组件
  2.定义组件
  3.将组件注册到路由中
  4.在vue中使用路由
  5.使用连接来设置路由
  6.设置占位
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4 <meta charset="UTF-8">
 5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7 <title>Document</title>   
 8 <script src="../vue2.4.4.js"></script>
 9 <!-- 1.引入文件 -->
10 <script src="../vue-router.js"></script>
11 </head>
12 
13 <body>
14 <!-- 定义一个vue的管理区块,(MVVM中的View) -->
15 <div id="app">
16     <!-- 5.这个是vueRouter中为我们提供的一个超链接,可以帮助我们点击,
17     点击以后跳转到相应的组件中
18           并且在组件中的内容展示在占位router-view -->
19     <router-link to="/login">登录</router-link>
20     <router-link to="/register">注册</router-link>
21     <!--  6.设置占位 -->
22    <router-view></router-view>
23 </div>
24 
25 </body>
26 
27 <script>
28     //2.定义组件
29     var login = Vue.extend({
30         template:"<h1>login</h1>"
31     });
32     var register = Vue.extend({
33         template:"<h1>register</h1>"
34     });
35 
36     // 3.将组件注册到路由中
37     var vueRouter = new VueRouter({//注册路由了
38         routes:[
39             {path:"/login",component:login},
40             {path:"/register",component:register},
41 
42         ]//数组,说明这里可以注册多个路由
43     });
44 
45     // 实例化vue对象(MVVM中的View Model)
46     new Vue({
47         // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析
48         el:'#app',
49         data:{
50         // 数据 (MVVM中的Model)   
51         },
52         // 4.在vue中使用路由
53         router:vueRouter
54 
55     })
56 </script>
57 </html>

二.使用vue中的路由给组件传递参数

参数传递分两步:
  1.第一步修改路由:
    在路由的路径后面加一个"/:" +键名
  2.将来在设置路由的连接上必须传入这个参数
    参数接受只要一步
    通过以下代码接收:
     this.$route.params.name
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4 <meta charset="UTF-8">
 5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7 <title>Document</title>   
 8 <script src="../vue2.4.4.js"></script>
 9 <!-- 1.引入文件 -->
10 <script src="../vue-router.js"></script>
11 </head>
12 
13 <body>
14 <!-- 定义一个vue的管理区块,(MVVM中的View) -->
15 <div id="app">
16     <!-- 5.这个是vueRouter中为我们提供的一个超链接,可以帮助我们点击,
17     点击以后跳转到相应的组件中
18           并且在组件中的内容展示在占位router-view -->
19     <router-link to="/login/nack">登录</router-link>
20     <router-link to="/register/20">注册</router-link>
21     <!--  6.设置占位 -->
22    <router-view></router-view>
23 </div>
24 
25 </body>
26 
27 <script>
28     //2.定义组件
29     var login = Vue.extend({
30         template:"<h1>login</h1>",
31         mounted:function(){
32             var name = this.$route.params.name;
33             alert(name);
34         }
35     });
36     var register = Vue.extend({
37         template:"<h1>register</h1>",
38         mounted:function(){
39             var age = this.$route.params.age;
40             alert(age);
41         }
42     });
43 
44     // 3.将组件注册到路由中
45     var vueRouter = new VueRouter({//注册路由了
46         routes:[
47             {path:"/login/:name",component:login},
48             {path:"/register/:age",component:register},
49 
50         ]//数组,说明这里可以注册多个路由
51     });
52 
53     // 实例化vue对象(MVVM中的View Model)
54     new Vue({
55         // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析
56         el:'#app',
57         data:{
58         // 数据 (MVVM中的Model)   
59         },
60         // 4.在vue中使用路由
61         router:vueRouter
62 
63     })
64 </script>
65 </html>

三.使用嵌套路由完成路由设置

嵌套组件:
  1.修改路由
  2.修改链接
  3.在父组件中添加占位
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4 <meta charset="UTF-8">
 5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7 <title>Document</title>   
 8 <script src="../vue2.4.4.js"></script>
 9 <!-- 1.引入文件 -->
10 <script src="../vue-router.js"></script>
11 </head>
12 
13 <body>
14 <!-- 定义一个vue的管理区块,(MVVM中的View) -->
15 <div id="app">
16     <!-- 5.这个是vueRouter中为我们提供的一个超链接,可以帮助我们点击,
17     点击以后跳转到相应的组件中
18           并且在组件中的内容展示在占位router-view -->
19     <router-link to="/account/login">登录</router-link>
20     <router-link to="/account/register">注册</router-link>
21     <!--  6.设置占位 -->
22    <router-view></router-view>
23 </div>
24 
25 
26 </body>
27 
28 <script>
29     //2.定义组件
30     var account = Vue.extend({
31         template:"<h1>account<router-view></router-view></h1>",
32     });
33     var login = Vue.extend({
34         template:"<h1>login</h1>",
35     });
36     var register = Vue.extend({
37         template:"<h1>register</h1>",
38     });
39 
40     // 3.将组件注册到路由中
41     var vueRouter = new VueRouter({//注册路由了
42         routes:[
43             {path:"/",redirect:"/account"},
44             // 在routers中只注册一个路由,将login和register加入这个路由中当作它的子路由(子组件)
45             {path:"/account",component:account,children:[
46                 {path:"login",component:login},
47                 {path:"register",component:register}
48             ]},
49         ]//数组,说明这里可以注册多个路由
50     });
51 
52     // 实例化vue对象(MVVM中的View Model)
53     new Vue({
54         // vm控制的区块为id为app的div,此div中的所有vue指令均可以被vm解析
55         el:'#app',
56         data:{
57         // 数据 (MVVM中的Model)   
58         },
59         // 4.在vue中使用路由
60         router:vueRouter
61     })
62 </script>
63 </html>

 

 
posted @ 2017-11-20 08:23  QinXiao.Shou  阅读(2149)  评论(0编辑  收藏  举报