liuyuqi-dellpc 6 years ago
parent
commit
d781d82bfd
52 changed files with 4215 additions and 56 deletions
  1. 6 0
      Advanced/vuedemo02/.babelrc
  2. 9 0
      Advanced/vuedemo02/.editorconfig
  3. 12 0
      Advanced/vuedemo02/.gitignore
  4. 18 0
      Advanced/vuedemo02/README.md
  5. 6 0
      Advanced/vuedemo02/build/index.js
  6. 19 0
      Advanced/vuedemo02/index.html
  7. 35 0
      Advanced/vuedemo02/package.json
  8. 27 0
      Advanced/vuedemo02/src/App.vue
  9. BIN
      Advanced/vuedemo02/src/assets/logo.png
  10. 1 0
      Advanced/vuedemo02/src/common/api.js
  11. 150 0
      Advanced/vuedemo02/src/common/common.js
  12. 9 0
      Advanced/vuedemo02/src/components/Home/Footer.vue
  13. 11 0
      Advanced/vuedemo02/src/components/Home/Header.vue
  14. 9 0
      Advanced/vuedemo02/src/components/Home/NewsDetail.vue
  15. 30 0
      Advanced/vuedemo02/src/components/Home/NewsList.vue
  16. 11 0
      Advanced/vuedemo02/src/main.js
  17. 9 0
      Advanced/vuedemo02/src/pages/Home/Index.vue
  18. 64 0
      Advanced/vuedemo02/src/pages/Home/v-bind.vue
  19. 62 0
      Advanced/vuedemo02/src/pages/Home/v-model双向数据绑定 .vue
  20. 88 0
      Advanced/vuedemo02/src/pages/Home/事件方法.vue
  21. 30 0
      Advanced/vuedemo02/src/pages/Home/生命周期函数.vue
  22. 47 0
      Advanced/vuedemo02/src/pages/Home/目标.vue
  23. 56 0
      Advanced/vuedemo02/src/pages/Home/绑定属性.vue
  24. 8 0
      Advanced/vuedemo02/src/pages/Home/请求数据.vue
  25. 26 0
      Advanced/vuedemo02/src/router/routers.js
  26. 10 0
      Advanced/vuedemo02/src/store/actions.js
  27. 5 0
      Advanced/vuedemo02/src/store/getters.js
  28. 17 0
      Advanced/vuedemo02/src/store/index.js
  29. 4 0
      Advanced/vuedemo02/src/store/mutation-types.js
  30. 16 0
      Advanced/vuedemo02/src/store/mutations.js
  31. 5 0
      Advanced/vuedemo02/src/store/state.js
  32. 78 0
      Advanced/vuedemo02/webpack.config.js
  33. 1 0
      Basic/js/axios.min.js
  34. 23 0
      Basic/js/filters.js
  35. 1 0
      Basic/js/jquery-2.1.1.min.js
  36. 2631 0
      Basic/js/vue-router.js
  37. 0 0
      Basic/js/vue-swipe.js
  38. 5 0
      Basic/js/vue.min.js
  39. 9 0
      Basic/vuex/session.html
  40. 9 0
      Basic/vuex/storage.html
  41. 57 0
      Basic/vuex/vuex.html
  42. 7 0
      Basic/监听属性/watch2.html
  43. 72 0
      Basic/组件/子组件之间传递数据.html
  44. 3 1
      Basic/网络/ajax_info.txt
  45. 40 0
      Basic/网络/axios请求数据.html
  46. 36 0
      Basic/表单/标签.html
  47. 67 55
      Basic/路由/index.html
  48. 52 0
      Basic/路由/vue-router.html
  49. 211 0
      Basic/路由/vue-router.md
  50. 51 0
      Basic/路由/vue-router2.html
  51. 61 0
      Basic/路由/vue-routername.html
  52. 1 0
      README.md

+ 6 - 0
Advanced/vuedemo02/.babelrc

@@ -0,0 +1,6 @@
+{
+  "presets": [
+    ["env", { "modules": false }],
+    "stage-3"
+  ]
+}

+ 9 - 0
Advanced/vuedemo02/.editorconfig

@@ -0,0 +1,9 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true

+ 12 - 0
Advanced/vuedemo02/.gitignore

@@ -0,0 +1,12 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log
+yarn-error.log
+
+# Editor directories and files
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln

+ 18 - 0
Advanced/vuedemo02/README.md

@@ -0,0 +1,18 @@
+# vuedemo02
+
+> A Vue.js project
+
+## Build Setup
+
+``` bash
+# install dependencies
+npm install
+
+# serve with hot reload at localhost:8080
+npm run dev
+
+# build for production with minification
+npm run build
+```
+
+For detailed explanation on how things work, consult the [docs for vue-loader](http://vuejs.github.io/vue-loader).

+ 6 - 0
Advanced/vuedemo02/build/index.js

@@ -0,0 +1,6 @@
+// see http://vuejs-templates.github.io/webpack for documentation.
+var path = require('path')
+
+module.exports = {
+   
+}

+ 19 - 0
Advanced/vuedemo02/index.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+
+	<head>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+		<meta name="description" content="">
+		<meta name="keywords" content="">
+		<title>vuedemo02</title>
+	</head>
+
+	<body>
+		<div id="app">
+		</div>
+		<script src="/dist/build.js"></script>
+	</body>
+
+</html>

+ 35 - 0
Advanced/vuedemo02/package.json

@@ -0,0 +1,35 @@
+{
+  "name": "vuedemo02",
+  "description": "A Vue.js project",
+  "version": "1.0.0",
+  "author": "liuyuqi-dellpc <liuyuqi.gov@msn.cn>",
+  "license": "MIT",
+  "private": true,
+  "scripts": {
+    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
+    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
+  },
+  "dependencies": {
+    "vue": "^2.5.11",
+    "vue-router": "^3.0.2"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ],
+  "devDependencies": {
+    "babel-core": "^6.26.0",
+    "babel-loader": "^7.1.2",
+    "babel-preset-env": "^1.6.0",
+    "babel-preset-stage-3": "^6.24.1",
+    "cross-env": "^5.0.5",
+    "css-loader": "^0.28.7",
+    "file-loader": "^1.1.4",
+    "sass-loader": "^7.1.0",
+    "vue-loader": "^13.0.5",
+    "vue-template-compiler": "^2.4.4",
+    "webpack": "^3.6.0",
+    "webpack-dev-server": "^2.9.1"
+  }
+}

+ 27 - 0
Advanced/vuedemo02/src/App.vue

@@ -0,0 +1,27 @@
+<template>
+	<div id="app">
+		<h2>{{msg}}</h2>
+		<div v-bind:title="title1">鼠标瞄上去看下效果</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		name: 'app',
+		data() {
+			return {
+				msg: "hello world!",
+				title1: "测试",
+			}
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.css_title2 {
+		color: #008000;
+	}
+</style>

BIN
Advanced/vuedemo02/src/assets/logo.png


+ 1 - 0
Advanced/vuedemo02/src/common/api.js

@@ -0,0 +1 @@
+

+ 150 - 0
Advanced/vuedemo02/src/common/common.js

@@ -0,0 +1,150 @@
+import _this from '../main'
+
+// 设置localStorage
+function setStorage(name, content) {
+    if (!name) return
+    if (typeof content !== 'string') {
+        content = JSON.stringify(content)
+    }
+    window.localStorage.setItem(name, content)
+}
+
+// 获取localStorage
+function getStorage(name) {
+    if (!name) return
+    return window.localStorage.getItem(name)
+}
+
+// 删除localStorage
+function removeStorage(name) {
+    if (!name) return
+    window.localStorage.removeItem(name)
+}
+
+// 把obj对象里的值覆盖到newobj里面
+function deepCopy(newobj, obj) {
+    if (typeof obj !== 'object') {
+        return obj
+    }
+    for (let attr in obj) {
+        let a = {}
+        if (newobj[attr]) {
+            a = newobj[attr]
+        }
+        newobj[attr] = deepCopy(a, obj[attr])
+    }
+    return newobj
+}
+
+// 跳转到登陆页面
+function jumpToLogin() {
+    _this.$router.push({
+        path: '/login',
+        query: {
+            redirect: _this.$route.fullPath
+        }
+    })
+}
+
+// 当出错的时候,显示错误信息,并且跳转
+function errorToBack(msg = '出错了,请重试', time = 1500) {
+    _this.$dialog.toast({
+        mes: msg,
+        timeout: time
+    })
+}
+// 操作成功后,的提示信息
+function successToShow(msg = '保存成功', callback = function() {}) {
+    // wx.showToast({
+    //   title: msg,
+    //   icon: 'success',
+    //   duration: 2000,
+    // });
+    // setTimeout(function () {
+    //   callback();
+    // }, 1500);
+}
+
+// 时间戳转时间格式
+function timeToDate(date) {
+    let dateTime = new Date(date * 1000) // 如果date为13位不需要乘1000
+    let Y = dateTime.getFullYear() + '-'
+    let M = (dateTime.getMonth() + 1 < 10 ? '0' + (dateTime.getMonth() + 1) : dateTime.getMonth() + 1) + '-'
+    let D = (dateTime.getDate() < 10 ? '0' + (dateTime.getDate()) : dateTime.getDate()) + ' '
+    let h = (dateTime.getHours() < 10 ? '0' + dateTime.getHours() : dateTime.getHours()) + ':'
+    let m = (dateTime.getMinutes() < 10 ? '0' + dateTime.getMinutes() : dateTime.getMinutes()) + ':'
+    let s = (dateTime.getSeconds() < 10 ? '0' + dateTime.getSeconds() : dateTime.getSeconds())
+    return Y + M + D + h + m + s
+}
+
+// 货币格式化
+function formatMoney(number, places, symbol, thousand, decimal) {
+    number = number || 0
+    places = !isNaN(places = Math.abs(places)) ? places : 2
+    symbol = symbol !== undefined ? symbol : '¥'
+    thousand = thousand || ','
+    decimal = decimal || '.'
+    let negative = number < 0 ? '-' : ''
+    let i = parseInt(number = Math.abs(+number || 0).toFixed(places), 10) + ''
+    let j = (i.length) > 3 ? i.length % 3 : 0
+    return symbol + negative + (j ? i.substr(0, j) + thousand : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand) + (places ? decimal + Math.abs(number - i).toFixed(places).slice(2) : '')
+}
+
+function throttle(fn, context, delay) {
+    clearTimeout(fn.timeoutId)
+    fn.timeoutId = setTimeout(function() {
+        fn.call(context)
+    }, delay)
+}
+
+// 获取验证码
+function getCaptcha() {
+    let randomNumber = Math.random() * 10 + 1
+    return window.apiUrl.replace('api', 'captcha') + '?' + randomNumber
+}
+
+function hecong() {
+    // 测试环境
+    let entId
+    if (process.env.NODE_ENV === 'development') {
+        entId = '10519'
+    } else if (process.env.NODE_ENV === 'production') {
+        // 正式环境
+        entId = window.entId
+    }
+    return entId
+}
+
+
+function locationHost () {
+    if (process.env.NODE_ENV === 'production') {
+        return window.apiUrl.split('/api.html')[0]
+    } else {
+        let url = 'http://www.b2c.com/index.php/api.html'
+        return url.split('/api.html')[0]
+    }
+}
+
+function isWeiXinBrowser () {
+    //window.navigator.userAgent属性包含了浏览器类型、版本、操作系统类型、浏览器引擎类型等信息,这个属性可以用来判断浏览器类型
+    let ua = window.navigator.userAgent.toLowerCase();
+    //通过正则表达式匹配ua中是否含有MicroMessenger字符串
+    return ua.match(/MicroMessenger/i) == 'micromessenger' ? true : false
+}
+
+export default {
+    setStorage: setStorage,
+    getStorage: getStorage,
+    removeStorage: removeStorage,
+    deepCopy: deepCopy,
+    jumpToLogin: jumpToLogin,
+    timeToDate: timeToDate,
+    formatMoney: formatMoney,
+    errorToBack: errorToBack,
+    successToShow: successToShow,
+    throttle: throttle,
+    getCaptcha: getCaptcha,
+    hecong: hecong,
+    locationHost: locationHost,
+    isWeiXinBrowser: isWeiXinBrowser
+}

+ 9 - 0
Advanced/vuedemo02/src/components/Home/Footer.vue

@@ -0,0 +1,9 @@
+<template>
+	<div>footer</div>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

+ 11 - 0
Advanced/vuedemo02/src/components/Home/Header.vue

@@ -0,0 +1,11 @@
+<template>
+	<div>
+		Header
+	</div>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

+ 9 - 0
Advanced/vuedemo02/src/components/Home/NewsDetail.vue

@@ -0,0 +1,9 @@
+<template>
+	<div>新闻详情页!</div>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

+ 30 - 0
Advanced/vuedemo02/src/components/Home/NewsList.vue

@@ -0,0 +1,30 @@
+<template>
+	<div>
+		<h3>新闻列表</h3>
+		<div>
+			<ol>
+				<li v-for="l in list">
+					<router-link to="/home/">{{首页}}</router>
+				</li>
+			</ol>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				msg: "hello world!",
+				list1: ["good", "bad", "nomal"]
+			}
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 11 - 0
Advanced/vuedemo02/src/main.js

@@ -0,0 +1,11 @@
+import Vue from 'vue'
+import App from './App.vue'
+//导入路由
+import routers from './router/routers'
+import VueRouter from 'vue-router'
+import * as Api from './common/api'
+
+new Vue({
+  el: '#app',
+  render: h => h(App)
+})

+ 9 - 0
Advanced/vuedemo02/src/pages/Home/Index.vue

@@ -0,0 +1,9 @@
+<template>
+	<div></div>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

+ 64 - 0
Advanced/vuedemo02/src/pages/Home/v-bind.vue

@@ -0,0 +1,64 @@
+<template>
+	<div id="app">
+		<h2>{{msg}}</h2>
+		<div v-bind:title="title1">鼠标瞄上去看下效果</div>
+		<div v-html="html1"></div>
+		<div v-text="text1">
+		</div>
+		<!-- 缩写 -->
+		<img :src="imageSrc">
+
+		<!-- 内联字符串拼接 -->
+		<img :src="'/path/to/images/' + fileName">
+
+		<!-- class 绑定 -->
+		<div :class="{ red: isRed }"></div>
+		<div :class="[classA, classB]"></div>
+		<div :class="[classA, { classB: isB, classC: isC }]"></div>
+
+		<!-- style 绑定 -->
+		<div :style="{ fontSize: size + 'px' }"></div>
+		<div :style="[styleObjectA, styleObjectB]"></div>
+
+		<!-- 绑定一个有属性的对象 -->
+		<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
+
+		<!-- 通过 prop 修饰符绑定 DOM 属性 -->
+		<div v-bind:text-content.prop="text"></div>
+
+		<!-- prop 绑定。“prop”必须在 my-component 中声明。-->
+		<my-component :prop="someThing"></my-component>
+
+		<!-- 通过 $props 将父组件的 props 一起传给子组件 -->
+		<child-component v-bind="$props"></child-component>
+
+		<!-- XLink -->
+		<svg>
+			<a :xlink:special="foo"></a>
+		</svg>
+	</div>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				msg: "hello world!",
+				title1: "测试",
+				url1: "https://www.baidu.com/img/bd_logo1.png",
+				text1: "测试text",
+				css_title: "{text-align: center;}",
+				html1: "<h2>html1</h2>",
+			}
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.css_title2 {
+		color: #008000;
+	}
+</style>

+ 62 - 0
Advanced/vuedemo02/src/pages/Home/v-model双向数据绑定 .vue

@@ -0,0 +1,62 @@
+<template>
+
+	<div id="app">
+
+		<h2>{{msg}}</h2>
+
+		<input type="text" v-model='msg' />
+
+		<button v-on:click="getMsg()">获取表单里面的数据get</button>
+
+		<button v-on:click="setMsg()">设置表单的数据set</button>
+
+		<input type="text" ref="userinfo" />
+		<br>
+		<br>
+		<div ref="box">我是一个box</div>
+		<button v-on:click="getInputValue()">获取第二个表单里面的数据</button>
+
+	</div>
+</template>
+
+<script>
+	export default {
+		data() { /*业务逻辑里面定义的数据*/
+			return {
+				msg: '你好vue'
+			}
+		},
+		methods: { /*放方法的地方*/
+
+			getMsg() {
+
+				// alert('vue方法执行了');
+
+				//方法里面获取data里面的数据
+
+				alert(this.msg);
+
+			},
+			setMsg() {
+				this.msg = "我是改变后的数据";
+
+			},
+			getInputValue() {
+
+				//获取ref定义的dom节点
+				console.log(this.$refs.userinfo);
+
+				this.$refs.box.style.background = 'red';
+
+				alert(this.$refs.userinfo.value);
+
+			}
+
+		}
+
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 88 - 0
Advanced/vuedemo02/src/pages/Home/事件方法.vue

@@ -0,0 +1,88 @@
+<template>
+	<div id="app">
+		{{msg}}
+		<br>
+		<button v-on:click="run1()">执行方法的第一种写法</button>
+		<br><br><br>
+		<button @click="run2()">执行方法的第二种写法</button>
+		<button @click="getMsg()">获取data里面的msg</button>
+		<button @click="setMsg()">改变data里面的msg</button>
+		<button @click="requestData()">请求数据</button>
+
+		<hr>
+
+		<ul>
+			<li v-for="(item,key) in list">
+				{{key}}--- {{item}}
+			</li>
+		</ul>
+
+		<br>
+		<br>
+		<br>
+		<button @click="deleteData('111')">执行方法传值111</button>
+
+		<br>
+		<br>
+		<button @click="deleteData('222')">执行方法传值2222</button>
+		<br>
+		<br>
+		<br>
+		<button data-aid='123' @click="eventFn($event)">事件对象</button>
+
+	</div>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				msg: '你好vue',
+				list: []
+			}
+		},
+		methods: {
+
+			run1: function() {
+
+				alert('这是一个方法');
+
+			},
+
+			run2() {
+				alert('这是另一个方法');
+			},
+			getMsg() {
+				alert(this.msg);
+			},
+			setMsg() {
+
+				this.msg = "我是改变后的数据"
+			},
+			requestData() {
+
+				for(var i = 0; i < 10; i++) {
+
+					this.list.push('我是第' + i + '条数据');
+				}
+			},
+			deleteData(val) {
+
+				alert(val);
+			},
+			eventFn(e) {
+				console.log(e);
+
+				// e.srcElement  dom节点
+
+				e.srcElement.style.background = 'red';
+
+				console.log(e.srcElement.dataset.aid); /*获取自定义属性的值*/
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 30 - 0
Advanced/vuedemo02/src/pages/Home/生命周期函数.vue

@@ -0,0 +1,30 @@
+<template>
+	
+</template>
+
+<script>
+		export default {
+		name: 'app',
+		data() {
+			return {
+				msg: "hello world!",
+				title1: "测试",
+				url1: "https://baidu.com",
+				text1: "测试text",
+				html1: "<h2>html1</h2>",
+				boxWdith: 500,
+				list: [1, 2, 3, 4, "hello"],
+				obj1: [{}, {}, {}]
+			}
+		},
+		methods: {
+			btnRun: function() {
+				alert("btn被点击了");
+				this.obj1.push("增加一条数据");
+			},
+		}
+	}
+</script>
+
+<style>
+</style>

+ 47 - 0
Advanced/vuedemo02/src/pages/Home/目标.vue

@@ -0,0 +1,47 @@
+<template>
+	<div id="app">
+
+	</div>
+</template>
+
+<script>
+	export default {
+		name: 'app',
+		data() {
+			return {
+				msg: "hello world!",
+			}
+		},
+		methods: {
+			btnRun: function() {},
+		},
+		beforeCreate() {
+			console.log("实例创建前");
+		},
+		created() {
+			console.log("实例已经创建");
+		},
+		beforeMount() {
+			console.log("实例挂载前");
+		},
+		mounted() {
+			console.log("实例已经挂载");
+		},
+		beforeUpdate() {
+			console.log("实例更新前");
+		},
+		updated() {
+			console.log("实例已经更新");
+		},
+		beforeDestroy() {
+			console.log("实例销毁前");
+		},
+		destroyed() {
+			console.log("实例已经销毁");
+		},
+	}
+</script>
+
+<style>
+
+</style>

+ 56 - 0
Advanced/vuedemo02/src/pages/Home/绑定属性.vue

@@ -0,0 +1,56 @@
+<template>
+	<div id="app">
+		<h2>{{msg}}</h2>
+		<div v-bind:title="title1">鼠标瞄上去看下效果</div>
+		<div :title="title1">鼠标瞄上去看下效果</div>
+		<img v-bind:src="url1" />
+		<div v-bind:class="css_title">绑定css</div>
+		<div v-bind:style="{'width':boxWdith+'px'}">测试</div>
+		<div v-html="html1"></div>
+		<div v-text="text1">
+			<button v-on:click="btnRun()">btn1</button>
+			<button @click="btnRun()">换一种写法</button>
+
+		</div>
+		<div>
+			<ol>
+				<li v-for="i in list">{{i}}</li>
+			</ol>
+		</div>
+		<div>
+			<ol>
+				<li v-for="(v,k) in obj1">{{k}}:{{v}}</li>
+			</ol>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		name: 'app',
+		data() {
+			return {
+				msg: "hello world!",
+				title1: "测试",
+				url1: "https://baidu.com",
+				text1: "测试text",
+				html1: "<h2>html1</h2>",
+				boxWdith: 500,
+				list: [1, 2, 3, 4, "hello"],
+				obj1: [{}, {}, {}]
+			}
+		},
+		methods: {
+			btnRun: function() {
+				alert("btn被点击了");
+				this.obj1.push("增加一条数据");
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.css_title {
+		color: #008000;
+	}
+</style>

+ 8 - 0
Advanced/vuedemo02/src/pages/Home/请求数据.vue

@@ -0,0 +1,8 @@
+<template>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

+ 26 - 0
Advanced/vuedemo02/src/router/routers.js

@@ -0,0 +1,26 @@
+/**
+ *      path         页面路由地址
+ *      navShow      是否显示页面头部
+ *      tabShow      是否显示页面底部导航
+ *      title        页面标题
+ *      keepAlive    是否缓存页面
+ *      @type {*[]}
+ */
+const routers = [
+    {
+        path: '/',
+        redirect: '/index'
+    },
+    {
+        path: '/index',
+        component: resolve => require(['../pages/Home/Index'], resolve),
+        name: 'Index',
+        meta: {
+            navShow: false,
+            tabShow: true,
+            keepAlive: true
+        }
+    }
+]
+
+export default routers

+ 10 - 0
Advanced/vuedemo02/src/store/actions.js

@@ -0,0 +1,10 @@
+import {
+    SAVE_STORE,
+    SAVE_SHIP,
+    SAVE_STORE_TAB
+} from './mutation-types'
+export const actions = {
+    saveStore: ({commit}, info) => commit(SAVE_STORE, info),
+    saveStoreTab: ({commit}, tab) => commit(SAVE_STORE_TAB, tab),
+    saveShip: ({commit}, info) => commit(SAVE_SHIP, info)
+}

+ 5 - 0
Advanced/vuedemo02/src/store/getters.js

@@ -0,0 +1,5 @@
+export const getters = {
+    storeInfo: state => state.storeInfo,
+    storeTab: state => state.storeTab,
+    shipInfo: state => state.shipInfo
+}

+ 17 - 0
Advanced/vuedemo02/src/store/index.js

@@ -0,0 +1,17 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import {state} from './state'
+import {getters} from './getters' // 导入响应的模块,*相当于引入了这个组件下所有导出的事例
+import {actions} from './actions'
+import {mutations} from './mutations'
+Vue.use(Vuex)
+
+// 注册上面引入的各大模块
+const store = new Vuex.Store({
+    state,    // 共同维护的一个状态,state里面可以是很多个全局状态
+    getters,  // 获取数据并渲染
+    actions,  // 数据的异步操作
+    mutations  // 处理数据的唯一途径,state的改变或赋值只能在这里
+})
+
+export default store  // 导出store并在 main.js中引用注册。

+ 4 - 0
Advanced/vuedemo02/src/store/mutation-types.js

@@ -0,0 +1,4 @@
+export const  SAVE_STORE = 'SAVE_STORE'
+export const SAVE_SHIP = 'SAVE_SHIP'
+export const SAVE_STORE_TAB = 'SAVE_STORE_TAB'
+

+ 16 - 0
Advanced/vuedemo02/src/store/mutations.js

@@ -0,0 +1,16 @@
+import {
+    SAVE_STORE,
+    SAVE_SHIP,
+    SAVE_STORE_TAB
+} from './mutation-types'
+export const mutations = {
+    [SAVE_STORE] (state, info) {
+        state.storeInfo = info
+    },
+    [SAVE_SHIP] (state, info) {
+        state.shipInfo = info
+    },
+    [SAVE_STORE_TAB] (state, tab) {
+        state.storeTab = tab
+    }
+}

+ 5 - 0
Advanced/vuedemo02/src/store/state.js

@@ -0,0 +1,5 @@
+export const state = {
+    storeInfo: {}, // 门店地址
+    shipInfo: {}, // 收货地址
+    storeTab: 0, // 门店默认tab页
+}

+ 78 - 0
Advanced/vuedemo02/webpack.config.js

@@ -0,0 +1,78 @@
+var path = require('path')
+var webpack = require('webpack')
+
+module.exports = {
+  entry: './src/main.js',
+  output: {
+    path: path.resolve(__dirname, './dist'),
+    publicPath: '/dist/',
+    filename: 'build.js'
+  },
+  module: {
+    rules: [
+      {
+        test: /\.css$/,
+        use: [
+          'vue-style-loader',
+          'css-loader'
+        ],
+      },      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: {
+          loaders: {
+          }
+          // other vue-loader options go here
+        }
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        exclude: /node_modules/
+      },
+      {
+        test: /\.(png|jpg|gif|svg)$/,
+        loader: 'file-loader',
+        options: {
+          name: '[name].[ext]?[hash]'
+        }
+      }
+    ]
+  },
+  resolve: {
+    alias: {
+      'vue$': 'vue/dist/vue.esm.js'
+    },
+    extensions: ['*', '.js', '.vue', '.json']
+  },
+  devServer: {
+    historyApiFallback: true,
+    noInfo: true,
+    overlay: true
+  },
+  performance: {
+    hints: false
+  },
+  devtool: '#eval-source-map'
+}
+
+if (process.env.NODE_ENV === 'production') {
+  module.exports.devtool = '#source-map'
+  // http://vue-loader.vuejs.org/en/workflow/production.html
+  module.exports.plugins = (module.exports.plugins || []).concat([
+    new webpack.DefinePlugin({
+      'process.env': {
+        NODE_ENV: '"production"'
+      }
+    }),
+    new webpack.optimize.UglifyJsPlugin({
+      sourceMap: true,
+      compress: {
+        warnings: false
+      }
+    }),
+    new webpack.LoaderOptionsPlugin({
+      minimize: true
+    })
+  ])
+}

File diff suppressed because it is too large
+ 1 - 0
Basic/js/axios.min.js


+ 23 - 0
Basic/js/filters.js

@@ -0,0 +1,23 @@
+/**
+ * 
+ * @authors Your Name (you@example.org)
+ * @date    2018-01-07 09:25:12
+ * 自定义过滤器,或许有用
+ */
+Vue.filter('date',function(time){
+	let oDate=new Date(time*1000);
+	//应该在年月日时分秒前面是否加0做判断
+	return oDate.getFullYear()+'-'+(oDate.getMoth()+1)+'-'+oData.getDate()
+			+' '+oDate.getHours()+':'oDate.getMinutex()+':'+oDate.getSeconds();
+})
+/*
+局部过滤器
+filters:{
+date(){
+	let oDate=new Date(time*1000);
+	//应该在年月日时分秒前面是否加0做判断
+	return oDate.getFullYear()+'-'+(oDate.getMoth()+1)+'-'+oData.getDate()
+			+' '+oDate.getHours()+':'oDate.getMinutex()+':'+oDate.getSeconds();
+}
+}
+*/

File diff suppressed because it is too large
+ 1 - 0
Basic/js/jquery-2.1.1.min.js


+ 2631 - 0
Basic/js/vue-router.js

@@ -0,0 +1,2631 @@
+/**
+  * vue-router v3.0.1
+  * (c) 2017 Evan You
+  * @license MIT
+  */
+(function (global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+	typeof define === 'function' && define.amd ? define(factory) :
+	(global.VueRouter = factory());
+}(this, (function () { 'use strict';
+
+/*  */
+
+function assert (condition, message) {
+  if (!condition) {
+    throw new Error(("[vue-router] " + message))
+  }
+}
+
+function warn (condition, message) {
+  if ("development" !== 'production' && !condition) {
+    typeof console !== 'undefined' && console.warn(("[vue-router] " + message));
+  }
+}
+
+function isError (err) {
+  return Object.prototype.toString.call(err).indexOf('Error') > -1
+}
+
+var View = {
+  name: 'router-view',
+  functional: true,
+  props: {
+    name: {
+      type: String,
+      default: 'default'
+    }
+  },
+  render: function render (_, ref) {
+    var props = ref.props;
+    var children = ref.children;
+    var parent = ref.parent;
+    var data = ref.data;
+
+    data.routerView = true;
+
+    // directly use parent context's createElement() function
+    // so that components rendered by router-view can resolve named slots
+    var h = parent.$createElement;
+    var name = props.name;
+    var route = parent.$route;
+    var cache = parent._routerViewCache || (parent._routerViewCache = {});
+
+    // determine current view depth, also check to see if the tree
+    // has been toggled inactive but kept-alive.
+    var depth = 0;
+    var inactive = false;
+    while (parent && parent._routerRoot !== parent) {
+      if (parent.$vnode && parent.$vnode.data.routerView) {
+        depth++;
+      }
+      if (parent._inactive) {
+        inactive = true;
+      }
+      parent = parent.$parent;
+    }
+    data.routerViewDepth = depth;
+
+    // render previous view if the tree is inactive and kept-alive
+    if (inactive) {
+      return h(cache[name], data, children)
+    }
+
+    var matched = route.matched[depth];
+    // render empty node if no matched route
+    if (!matched) {
+      cache[name] = null;
+      return h()
+    }
+
+    var component = cache[name] = matched.components[name];
+
+    // attach instance registration hook
+    // this will be called in the instance's injected lifecycle hooks
+    data.registerRouteInstance = function (vm, val) {
+      // val could be undefined for unregistration
+      var current = matched.instances[name];
+      if (
+        (val && current !== vm) ||
+        (!val && current === vm)
+      ) {
+        matched.instances[name] = val;
+      }
+    }
+
+    // also register instance in prepatch hook
+    // in case the same component instance is reused across different routes
+    ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {
+      matched.instances[name] = vnode.componentInstance;
+    };
+
+    // resolve props
+    var propsToPass = data.props = resolveProps(route, matched.props && matched.props[name]);
+    if (propsToPass) {
+      // clone to prevent mutation
+      propsToPass = data.props = extend({}, propsToPass);
+      // pass non-declared props as attrs
+      var attrs = data.attrs = data.attrs || {};
+      for (var key in propsToPass) {
+        if (!component.props || !(key in component.props)) {
+          attrs[key] = propsToPass[key];
+          delete propsToPass[key];
+        }
+      }
+    }
+
+    return h(component, data, children)
+  }
+};
+
+function resolveProps (route, config) {
+  switch (typeof config) {
+    case 'undefined':
+      return
+    case 'object':
+      return config
+    case 'function':
+      return config(route)
+    case 'boolean':
+      return config ? route.params : undefined
+    default:
+      {
+        warn(
+          false,
+          "props in \"" + (route.path) + "\" is a " + (typeof config) + ", " +
+          "expecting an object, function or boolean."
+        );
+      }
+  }
+}
+
+function extend (to, from) {
+  for (var key in from) {
+    to[key] = from[key];
+  }
+  return to
+}
+
+/*  */
+
+var encodeReserveRE = /[!'()*]/g;
+var encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };
+var commaRE = /%2C/g;
+
+// fixed encodeURIComponent which is more conformant to RFC3986:
+// - escapes [!'()*]
+// - preserve commas
+var encode = function (str) { return encodeURIComponent(str)
+  .replace(encodeReserveRE, encodeReserveReplacer)
+  .replace(commaRE, ','); };
+
+var decode = decodeURIComponent;
+
+function resolveQuery (
+  query,
+  extraQuery,
+  _parseQuery
+) {
+  if ( extraQuery === void 0 ) extraQuery = {};
+
+  var parse = _parseQuery || parseQuery;
+  var parsedQuery;
+  try {
+    parsedQuery = parse(query || '');
+  } catch (e) {
+    "development" !== 'production' && warn(false, e.message);
+    parsedQuery = {};
+  }
+  for (var key in extraQuery) {
+    parsedQuery[key] = extraQuery[key];
+  }
+  return parsedQuery
+}
+
+function parseQuery (query) {
+  var res = {};
+
+  query = query.trim().replace(/^(\?|#|&)/, '');
+
+  if (!query) {
+    return res
+  }
+
+  query.split('&').forEach(function (param) {
+    var parts = param.replace(/\+/g, ' ').split('=');
+    var key = decode(parts.shift());
+    var val = parts.length > 0
+      ? decode(parts.join('='))
+      : null;
+
+    if (res[key] === undefined) {
+      res[key] = val;
+    } else if (Array.isArray(res[key])) {
+      res[key].push(val);
+    } else {
+      res[key] = [res[key], val];
+    }
+  });
+
+  return res
+}
+
+function stringifyQuery (obj) {
+  var res = obj ? Object.keys(obj).map(function (key) {
+    var val = obj[key];
+
+    if (val === undefined) {
+      return ''
+    }
+
+    if (val === null) {
+      return encode(key)
+    }
+
+    if (Array.isArray(val)) {
+      var result = [];
+      val.forEach(function (val2) {
+        if (val2 === undefined) {
+          return
+        }
+        if (val2 === null) {
+          result.push(encode(key));
+        } else {
+          result.push(encode(key) + '=' + encode(val2));
+        }
+      });
+      return result.join('&')
+    }
+
+    return encode(key) + '=' + encode(val)
+  }).filter(function (x) { return x.length > 0; }).join('&') : null;
+  return res ? ("?" + res) : ''
+}
+
+/*  */
+
+
+var trailingSlashRE = /\/?$/;
+
+function createRoute (
+  record,
+  location,
+  redirectedFrom,
+  router
+) {
+  var stringifyQuery$$1 = router && router.options.stringifyQuery;
+
+  var query = location.query || {};
+  try {
+    query = clone(query);
+  } catch (e) {}
+
+  var route = {
+    name: location.name || (record && record.name),
+    meta: (record && record.meta) || {},
+    path: location.path || '/',
+    hash: location.hash || '',
+    query: query,
+    params: location.params || {},
+    fullPath: getFullPath(location, stringifyQuery$$1),
+    matched: record ? formatMatch(record) : []
+  };
+  if (redirectedFrom) {
+    route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery$$1);
+  }
+  return Object.freeze(route)
+}
+
+function clone (value) {
+  if (Array.isArray(value)) {
+    return value.map(clone)
+  } else if (value && typeof value === 'object') {
+    var res = {};
+    for (var key in value) {
+      res[key] = clone(value[key]);
+    }
+    return res
+  } else {
+    return value
+  }
+}
+
+// the starting route that represents the initial state
+var START = createRoute(null, {
+  path: '/'
+});
+
+function formatMatch (record) {
+  var res = [];
+  while (record) {
+    res.unshift(record);
+    record = record.parent;
+  }
+  return res
+}
+
+function getFullPath (
+  ref,
+  _stringifyQuery
+) {
+  var path = ref.path;
+  var query = ref.query; if ( query === void 0 ) query = {};
+  var hash = ref.hash; if ( hash === void 0 ) hash = '';
+
+  var stringify = _stringifyQuery || stringifyQuery;
+  return (path || '/') + stringify(query) + hash
+}
+
+function isSameRoute (a, b) {
+  if (b === START) {
+    return a === b
+  } else if (!b) {
+    return false
+  } else if (a.path && b.path) {
+    return (
+      a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
+      a.hash === b.hash &&
+      isObjectEqual(a.query, b.query)
+    )
+  } else if (a.name && b.name) {
+    return (
+      a.name === b.name &&
+      a.hash === b.hash &&
+      isObjectEqual(a.query, b.query) &&
+      isObjectEqual(a.params, b.params)
+    )
+  } else {
+    return false
+  }
+}
+
+function isObjectEqual (a, b) {
+  if ( a === void 0 ) a = {};
+  if ( b === void 0 ) b = {};
+
+  // handle null value #1566
+  if (!a || !b) { return a === b }
+  var aKeys = Object.keys(a);
+  var bKeys = Object.keys(b);
+  if (aKeys.length !== bKeys.length) {
+    return false
+  }
+  return aKeys.every(function (key) {
+    var aVal = a[key];
+    var bVal = b[key];
+    // check nested equality
+    if (typeof aVal === 'object' && typeof bVal === 'object') {
+      return isObjectEqual(aVal, bVal)
+    }
+    return String(aVal) === String(bVal)
+  })
+}
+
+function isIncludedRoute (current, target) {
+  return (
+    current.path.replace(trailingSlashRE, '/').indexOf(
+      target.path.replace(trailingSlashRE, '/')
+    ) === 0 &&
+    (!target.hash || current.hash === target.hash) &&
+    queryIncludes(current.query, target.query)
+  )
+}
+
+function queryIncludes (current, target) {
+  for (var key in target) {
+    if (!(key in current)) {
+      return false
+    }
+  }
+  return true
+}
+
+/*  */
+
+// work around weird flow bug
+var toTypes = [String, Object];
+var eventTypes = [String, Array];
+
+var Link = {
+  name: 'router-link',
+  props: {
+    to: {
+      type: toTypes,
+      required: true
+    },
+    tag: {
+      type: String,
+      default: 'a'
+    },
+    exact: Boolean,
+    append: Boolean,
+    replace: Boolean,
+    activeClass: String,
+    exactActiveClass: String,
+    event: {
+      type: eventTypes,
+      default: 'click'
+    }
+  },
+  render: function render (h) {
+    var this$1 = this;
+
+    var router = this.$router;
+    var current = this.$route;
+    var ref = router.resolve(this.to, current, this.append);
+    var location = ref.location;
+    var route = ref.route;
+    var href = ref.href;
+
+    var classes = {};
+    var globalActiveClass = router.options.linkActiveClass;
+    var globalExactActiveClass = router.options.linkExactActiveClass;
+    // Support global empty active class
+    var activeClassFallback = globalActiveClass == null
+            ? 'router-link-active'
+            : globalActiveClass;
+    var exactActiveClassFallback = globalExactActiveClass == null
+            ? 'router-link-exact-active'
+            : globalExactActiveClass;
+    var activeClass = this.activeClass == null
+            ? activeClassFallback
+            : this.activeClass;
+    var exactActiveClass = this.exactActiveClass == null
+            ? exactActiveClassFallback
+            : this.exactActiveClass;
+    var compareTarget = location.path
+      ? createRoute(null, location, null, router)
+      : route;
+
+    classes[exactActiveClass] = isSameRoute(current, compareTarget);
+    classes[activeClass] = this.exact
+      ? classes[exactActiveClass]
+      : isIncludedRoute(current, compareTarget);
+
+    var handler = function (e) {
+      if (guardEvent(e)) {
+        if (this$1.replace) {
+          router.replace(location);
+        } else {
+          router.push(location);
+        }
+      }
+    };
+
+    var on = { click: guardEvent };
+    if (Array.isArray(this.event)) {
+      this.event.forEach(function (e) { on[e] = handler; });
+    } else {
+      on[this.event] = handler;
+    }
+
+    var data = {
+      class: classes
+    };
+
+    if (this.tag === 'a') {
+      data.on = on;
+      data.attrs = { href: href };
+    } else {
+      // find the first <a> child and apply listener and href
+      var a = findAnchor(this.$slots.default);
+      if (a) {
+        // in case the <a> is a static node
+        a.isStatic = false;
+        var extend = _Vue.util.extend;
+        var aData = a.data = extend({}, a.data);
+        aData.on = on;
+        var aAttrs = a.data.attrs = extend({}, a.data.attrs);
+        aAttrs.href = href;
+      } else {
+        // doesn't have <a> child, apply listener to self
+        data.on = on;
+      }
+    }
+
+    return h(this.tag, data, this.$slots.default)
+  }
+};
+
+function guardEvent (e) {
+  // don't redirect with control keys
+  if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
+  // don't redirect when preventDefault called
+  if (e.defaultPrevented) { return }
+  // don't redirect on right click
+  if (e.button !== undefined && e.button !== 0) { return }
+  // don't redirect if `target="_blank"`
+  if (e.currentTarget && e.currentTarget.getAttribute) {
+    var target = e.currentTarget.getAttribute('target');
+    if (/\b_blank\b/i.test(target)) { return }
+  }
+  // this may be a Weex event which doesn't have this method
+  if (e.preventDefault) {
+    e.preventDefault();
+  }
+  return true
+}
+
+function findAnchor (children) {
+  if (children) {
+    var child;
+    for (var i = 0; i < children.length; i++) {
+      child = children[i];
+      if (child.tag === 'a') {
+        return child
+      }
+      if (child.children && (child = findAnchor(child.children))) {
+        return child
+      }
+    }
+  }
+}
+
+var _Vue;
+
+function install (Vue) {
+  if (install.installed && _Vue === Vue) { return }
+  install.installed = true;
+
+  _Vue = Vue;
+
+  var isDef = function (v) { return v !== undefined; };
+
+  var registerInstance = function (vm, callVal) {
+    var i = vm.$options._parentVnode;
+    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
+      i(vm, callVal);
+    }
+  };
+
+  Vue.mixin({
+    beforeCreate: function beforeCreate () {
+      if (isDef(this.$options.router)) {
+        this._routerRoot = this;
+        this._router = this.$options.router;
+        this._router.init(this);
+        Vue.util.defineReactive(this, '_route', this._router.history.current);
+      } else {
+        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
+      }
+      registerInstance(this, this);
+    },
+    destroyed: function destroyed () {
+      registerInstance(this);
+    }
+  });
+
+  Object.defineProperty(Vue.prototype, '$router', {
+    get: function get () { return this._routerRoot._router }
+  });
+
+  Object.defineProperty(Vue.prototype, '$route', {
+    get: function get () { return this._routerRoot._route }
+  });
+
+  Vue.component('router-view', View);
+  Vue.component('router-link', Link);
+
+  var strats = Vue.config.optionMergeStrategies;
+  // use the same hook merging strategy for route hooks
+  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;
+}
+
+/*  */
+
+var inBrowser = typeof window !== 'undefined';
+
+/*  */
+
+function resolvePath (
+  relative,
+  base,
+  append
+) {
+  var firstChar = relative.charAt(0);
+  if (firstChar === '/') {
+    return relative
+  }
+
+  if (firstChar === '?' || firstChar === '#') {
+    return base + relative
+  }
+
+  var stack = base.split('/');
+
+  // remove trailing segment if:
+  // - not appending
+  // - appending to trailing slash (last segment is empty)
+  if (!append || !stack[stack.length - 1]) {
+    stack.pop();
+  }
+
+  // resolve relative path
+  var segments = relative.replace(/^\//, '').split('/');
+  for (var i = 0; i < segments.length; i++) {
+    var segment = segments[i];
+    if (segment === '..') {
+      stack.pop();
+    } else if (segment !== '.') {
+      stack.push(segment);
+    }
+  }
+
+  // ensure leading slash
+  if (stack[0] !== '') {
+    stack.unshift('');
+  }
+
+  return stack.join('/')
+}
+
+function parsePath (path) {
+  var hash = '';
+  var query = '';
+
+  var hashIndex = path.indexOf('#');
+  if (hashIndex >= 0) {
+    hash = path.slice(hashIndex);
+    path = path.slice(0, hashIndex);
+  }
+
+  var queryIndex = path.indexOf('?');
+  if (queryIndex >= 0) {
+    query = path.slice(queryIndex + 1);
+    path = path.slice(0, queryIndex);
+  }
+
+  return {
+    path: path,
+    query: query,
+    hash: hash
+  }
+}
+
+function cleanPath (path) {
+  return path.replace(/\/\//g, '/')
+}
+
+var isarray = Array.isArray || function (arr) {
+  return Object.prototype.toString.call(arr) == '[object Array]';
+};
+
+/**
+ * Expose `pathToRegexp`.
+ */
+var pathToRegexp_1 = pathToRegexp;
+var parse_1 = parse;
+var compile_1 = compile;
+var tokensToFunction_1 = tokensToFunction;
+var tokensToRegExp_1 = tokensToRegExp;
+
+/**
+ * The main path matching regexp utility.
+ *
+ * @type {RegExp}
+ */
+var PATH_REGEXP = new RegExp([
+  // Match escaped characters that would otherwise appear in future matches.
+  // This allows the user to escape special characters that won't transform.
+  '(\\\\.)',
+  // Match Express-style parameters and un-named parameters with a prefix
+  // and optional suffixes. Matches appear as:
+  //
+  // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
+  // "/route(\\d+)"  => [undefined, undefined, undefined, "\d+", undefined, undefined]
+  // "/*"            => ["/", undefined, undefined, undefined, undefined, "*"]
+  '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
+].join('|'), 'g');
+
+/**
+ * Parse a string for the raw tokens.
+ *
+ * @param  {string}  str
+ * @param  {Object=} options
+ * @return {!Array}
+ */
+function parse (str, options) {
+  var tokens = [];
+  var key = 0;
+  var index = 0;
+  var path = '';
+  var defaultDelimiter = options && options.delimiter || '/';
+  var res;
+
+  while ((res = PATH_REGEXP.exec(str)) != null) {
+    var m = res[0];
+    var escaped = res[1];
+    var offset = res.index;
+    path += str.slice(index, offset);
+    index = offset + m.length;
+
+    // Ignore already escaped sequences.
+    if (escaped) {
+      path += escaped[1];
+      continue
+    }
+
+    var next = str[index];
+    var prefix = res[2];
+    var name = res[3];
+    var capture = res[4];
+    var group = res[5];
+    var modifier = res[6];
+    var asterisk = res[7];
+
+    // Push the current path onto the tokens.
+    if (path) {
+      tokens.push(path);
+      path = '';
+    }
+
+    var partial = prefix != null && next != null && next !== prefix;
+    var repeat = modifier === '+' || modifier === '*';
+    var optional = modifier === '?' || modifier === '*';
+    var delimiter = res[2] || defaultDelimiter;
+    var pattern = capture || group;
+
+    tokens.push({
+      name: name || key++,
+      prefix: prefix || '',
+      delimiter: delimiter,
+      optional: optional,
+      repeat: repeat,
+      partial: partial,
+      asterisk: !!asterisk,
+      pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
+    });
+  }
+
+  // Match any characters still remaining.
+  if (index < str.length) {
+    path += str.substr(index);
+  }
+
+  // If the path exists, push it onto the end.
+  if (path) {
+    tokens.push(path);
+  }
+
+  return tokens
+}
+
+/**
+ * Compile a string to a template function for the path.
+ *
+ * @param  {string}             str
+ * @param  {Object=}            options
+ * @return {!function(Object=, Object=)}
+ */
+function compile (str, options) {
+  return tokensToFunction(parse(str, options))
+}
+
+/**
+ * Prettier encoding of URI path segments.
+ *
+ * @param  {string}
+ * @return {string}
+ */
+function encodeURIComponentPretty (str) {
+  return encodeURI(str).replace(/[\/?#]/g, function (c) {
+    return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+  })
+}
+
+/**
+ * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
+ *
+ * @param  {string}
+ * @return {string}
+ */
+function encodeAsterisk (str) {
+  return encodeURI(str).replace(/[?#]/g, function (c) {
+    return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+  })
+}
+
+/**
+ * Expose a method for transforming tokens into the path function.
+ */
+function tokensToFunction (tokens) {
+  // Compile all the tokens into regexps.
+  var matches = new Array(tokens.length);
+
+  // Compile all the patterns before compilation.
+  for (var i = 0; i < tokens.length; i++) {
+    if (typeof tokens[i] === 'object') {
+      matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
+    }
+  }
+
+  return function (obj, opts) {
+    var path = '';
+    var data = obj || {};
+    var options = opts || {};
+    var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
+
+    for (var i = 0; i < tokens.length; i++) {
+      var token = tokens[i];
+
+      if (typeof token === 'string') {
+        path += token;
+
+        continue
+      }
+
+      var value = data[token.name];
+      var segment;
+
+      if (value == null) {
+        if (token.optional) {
+          // Prepend partial segment prefixes.
+          if (token.partial) {
+            path += token.prefix;
+          }
+
+          continue
+        } else {
+          throw new TypeError('Expected "' + token.name + '" to be defined')
+        }
+      }
+
+      if (isarray(value)) {
+        if (!token.repeat) {
+          throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
+        }
+
+        if (value.length === 0) {
+          if (token.optional) {
+            continue
+          } else {
+            throw new TypeError('Expected "' + token.name + '" to not be empty')
+          }
+        }
+
+        for (var j = 0; j < value.length; j++) {
+          segment = encode(value[j]);
+
+          if (!matches[i].test(segment)) {
+            throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
+          }
+
+          path += (j === 0 ? token.prefix : token.delimiter) + segment;
+        }
+
+        continue
+      }
+
+      segment = token.asterisk ? encodeAsterisk(value) : encode(value);
+
+      if (!matches[i].test(segment)) {
+        throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
+      }
+
+      path += token.prefix + segment;
+    }
+
+    return path
+  }
+}
+
+/**
+ * Escape a regular expression string.
+ *
+ * @param  {string} str
+ * @return {string}
+ */
+function escapeString (str) {
+  return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
+}
+
+/**
+ * Escape the capturing group by escaping special characters and meaning.
+ *
+ * @param  {string} group
+ * @return {string}
+ */
+function escapeGroup (group) {
+  return group.replace(/([=!:$\/()])/g, '\\$1')
+}
+
+/**
+ * Attach the keys as a property of the regexp.
+ *
+ * @param  {!RegExp} re
+ * @param  {Array}   keys
+ * @return {!RegExp}
+ */
+function attachKeys (re, keys) {
+  re.keys = keys;
+  return re
+}
+
+/**
+ * Get the flags for a regexp from the options.
+ *
+ * @param  {Object} options
+ * @return {string}
+ */
+function flags (options) {
+  return options.sensitive ? '' : 'i'
+}
+
+/**
+ * Pull out keys from a regexp.
+ *
+ * @param  {!RegExp} path
+ * @param  {!Array}  keys
+ * @return {!RegExp}
+ */
+function regexpToRegexp (path, keys) {
+  // Use a negative lookahead to match only capturing groups.
+  var groups = path.source.match(/\((?!\?)/g);
+
+  if (groups) {
+    for (var i = 0; i < groups.length; i++) {
+      keys.push({
+        name: i,
+        prefix: null,
+        delimiter: null,
+        optional: false,
+        repeat: false,
+        partial: false,
+        asterisk: false,
+        pattern: null
+      });
+    }
+  }
+
+  return attachKeys(path, keys)
+}
+
+/**
+ * Transform an array into a regexp.
+ *
+ * @param  {!Array}  path
+ * @param  {Array}   keys
+ * @param  {!Object} options
+ * @return {!RegExp}
+ */
+function arrayToRegexp (path, keys, options) {
+  var parts = [];
+
+  for (var i = 0; i < path.length; i++) {
+    parts.push(pathToRegexp(path[i], keys, options).source);
+  }
+
+  var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
+
+  return attachKeys(regexp, keys)
+}
+
+/**
+ * Create a path regexp from string input.
+ *
+ * @param  {string}  path
+ * @param  {!Array}  keys
+ * @param  {!Object} options
+ * @return {!RegExp}
+ */
+function stringToRegexp (path, keys, options) {
+  return tokensToRegExp(parse(path, options), keys, options)
+}
+
+/**
+ * Expose a function for taking tokens and returning a RegExp.
+ *
+ * @param  {!Array}          tokens
+ * @param  {(Array|Object)=} keys
+ * @param  {Object=}         options
+ * @return {!RegExp}
+ */
+function tokensToRegExp (tokens, keys, options) {
+  if (!isarray(keys)) {
+    options = /** @type {!Object} */ (keys || options);
+    keys = [];
+  }
+
+  options = options || {};
+
+  var strict = options.strict;
+  var end = options.end !== false;
+  var route = '';
+
+  // Iterate over the tokens and create our regexp string.
+  for (var i = 0; i < tokens.length; i++) {
+    var token = tokens[i];
+
+    if (typeof token === 'string') {
+      route += escapeString(token);
+    } else {
+      var prefix = escapeString(token.prefix);
+      var capture = '(?:' + token.pattern + ')';
+
+      keys.push(token);
+
+      if (token.repeat) {
+        capture += '(?:' + prefix + capture + ')*';
+      }
+
+      if (token.optional) {
+        if (!token.partial) {
+          capture = '(?:' + prefix + '(' + capture + '))?';
+        } else {
+          capture = prefix + '(' + capture + ')?';
+        }
+      } else {
+        capture = prefix + '(' + capture + ')';
+      }
+
+      route += capture;
+    }
+  }
+
+  var delimiter = escapeString(options.delimiter || '/');
+  var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
+
+  // In non-strict mode we allow a slash at the end of match. If the path to
+  // match already ends with a slash, we remove it for consistency. The slash
+  // is valid at the end of a path match, not in the middle. This is important
+  // in non-ending mode, where "/test/" shouldn't match "/test//route".
+  if (!strict) {
+    route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
+  }
+
+  if (end) {
+    route += '$';
+  } else {
+    // In non-ending mode, we need the capturing groups to match as much as
+    // possible by using a positive lookahead to the end or next path segment.
+    route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
+  }
+
+  return attachKeys(new RegExp('^' + route, flags(options)), keys)
+}
+
+/**
+ * Normalize the given path string, returning a regular expression.
+ *
+ * An empty array can be passed in for the keys, which will hold the
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
+ *
+ * @param  {(string|RegExp|Array)} path
+ * @param  {(Array|Object)=}       keys
+ * @param  {Object=}               options
+ * @return {!RegExp}
+ */
+function pathToRegexp (path, keys, options) {
+  if (!isarray(keys)) {
+    options = /** @type {!Object} */ (keys || options);
+    keys = [];
+  }
+
+  options = options || {};
+
+  if (path instanceof RegExp) {
+    return regexpToRegexp(path, /** @type {!Array} */ (keys))
+  }
+
+  if (isarray(path)) {
+    return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
+  }
+
+  return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
+}
+
+pathToRegexp_1.parse = parse_1;
+pathToRegexp_1.compile = compile_1;
+pathToRegexp_1.tokensToFunction = tokensToFunction_1;
+pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
+
+/*  */
+
+// $flow-disable-line
+var regexpCompileCache = Object.create(null);
+
+function fillParams (
+  path,
+  params,
+  routeMsg
+) {
+  try {
+    var filler =
+      regexpCompileCache[path] ||
+      (regexpCompileCache[path] = pathToRegexp_1.compile(path));
+    return filler(params || {}, { pretty: true })
+  } catch (e) {
+    {
+      warn(false, ("missing param for " + routeMsg + ": " + (e.message)));
+    }
+    return ''
+  }
+}
+
+/*  */
+
+function createRouteMap (
+  routes,
+  oldPathList,
+  oldPathMap,
+  oldNameMap
+) {
+  // the path list is used to control path matching priority
+  var pathList = oldPathList || [];
+  // $flow-disable-line
+  var pathMap = oldPathMap || Object.create(null);
+  // $flow-disable-line
+  var nameMap = oldNameMap || Object.create(null);
+
+  routes.forEach(function (route) {
+    addRouteRecord(pathList, pathMap, nameMap, route);
+  });
+
+  // ensure wildcard routes are always at the end
+  for (var i = 0, l = pathList.length; i < l; i++) {
+    if (pathList[i] === '*') {
+      pathList.push(pathList.splice(i, 1)[0]);
+      l--;
+      i--;
+    }
+  }
+
+  return {
+    pathList: pathList,
+    pathMap: pathMap,
+    nameMap: nameMap
+  }
+}
+
+function addRouteRecord (
+  pathList,
+  pathMap,
+  nameMap,
+  route,
+  parent,
+  matchAs
+) {
+  var path = route.path;
+  var name = route.name;
+  {
+    assert(path != null, "\"path\" is required in a route configuration.");
+    assert(
+      typeof route.component !== 'string',
+      "route config \"component\" for path: " + (String(path || name)) + " cannot be a " +
+      "string id. Use an actual component instead."
+    );
+  }
+
+  var pathToRegexpOptions = route.pathToRegexpOptions || {};
+  var normalizedPath = normalizePath(
+    path,
+    parent,
+    pathToRegexpOptions.strict
+  );
+
+  if (typeof route.caseSensitive === 'boolean') {
+    pathToRegexpOptions.sensitive = route.caseSensitive;
+  }
+
+  var record = {
+    path: normalizedPath,
+    regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
+    components: route.components || { default: route.component },
+    instances: {},
+    name: name,
+    parent: parent,
+    matchAs: matchAs,
+    redirect: route.redirect,
+    beforeEnter: route.beforeEnter,
+    meta: route.meta || {},
+    props: route.props == null
+      ? {}
+      : route.components
+        ? route.props
+        : { default: route.props }
+  };
+
+  if (route.children) {
+    // Warn if route is named, does not redirect and has a default child route.
+    // If users navigate to this route by name, the default child will
+    // not be rendered (GH Issue #629)
+    {
+      if (route.name && !route.redirect && route.children.some(function (child) { return /^\/?$/.test(child.path); })) {
+        warn(
+          false,
+          "Named Route '" + (route.name) + "' has a default child route. " +
+          "When navigating to this named route (:to=\"{name: '" + (route.name) + "'\"), " +
+          "the default child route will not be rendered. Remove the name from " +
+          "this route and use the name of the default child route for named " +
+          "links instead."
+        );
+      }
+    }
+    route.children.forEach(function (child) {
+      var childMatchAs = matchAs
+        ? cleanPath((matchAs + "/" + (child.path)))
+        : undefined;
+      addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);
+    });
+  }
+
+  if (route.alias !== undefined) {
+    var aliases = Array.isArray(route.alias)
+      ? route.alias
+      : [route.alias];
+
+    aliases.forEach(function (alias) {
+      var aliasRoute = {
+        path: alias,
+        children: route.children
+      };
+      addRouteRecord(
+        pathList,
+        pathMap,
+        nameMap,
+        aliasRoute,
+        parent,
+        record.path || '/' // matchAs
+      );
+    });
+  }
+
+  if (!pathMap[record.path]) {
+    pathList.push(record.path);
+    pathMap[record.path] = record;
+  }
+
+  if (name) {
+    if (!nameMap[name]) {
+      nameMap[name] = record;
+    } else if ("development" !== 'production' && !matchAs) {
+      warn(
+        false,
+        "Duplicate named routes definition: " +
+        "{ name: \"" + name + "\", path: \"" + (record.path) + "\" }"
+      );
+    }
+  }
+}
+
+function compileRouteRegex (path, pathToRegexpOptions) {
+  var regex = pathToRegexp_1(path, [], pathToRegexpOptions);
+  {
+    var keys = Object.create(null);
+    regex.keys.forEach(function (key) {
+      warn(!keys[key.name], ("Duplicate param keys in route with path: \"" + path + "\""));
+      keys[key.name] = true;
+    });
+  }
+  return regex
+}
+
+function normalizePath (path, parent, strict) {
+  if (!strict) { path = path.replace(/\/$/, ''); }
+  if (path[0] === '/') { return path }
+  if (parent == null) { return path }
+  return cleanPath(((parent.path) + "/" + path))
+}
+
+/*  */
+
+
+function normalizeLocation (
+  raw,
+  current,
+  append,
+  router
+) {
+  var next = typeof raw === 'string' ? { path: raw } : raw;
+  // named target
+  if (next.name || next._normalized) {
+    return next
+  }
+
+  // relative params
+  if (!next.path && next.params && current) {
+    next = assign({}, next);
+    next._normalized = true;
+    var params = assign(assign({}, current.params), next.params);
+    if (current.name) {
+      next.name = current.name;
+      next.params = params;
+    } else if (current.matched.length) {
+      var rawPath = current.matched[current.matched.length - 1].path;
+      next.path = fillParams(rawPath, params, ("path " + (current.path)));
+    } else {
+      warn(false, "relative params navigation requires a current route.");
+    }
+    return next
+  }
+
+  var parsedPath = parsePath(next.path || '');
+  var basePath = (current && current.path) || '/';
+  var path = parsedPath.path
+    ? resolvePath(parsedPath.path, basePath, append || next.append)
+    : basePath;
+
+  var query = resolveQuery(
+    parsedPath.query,
+    next.query,
+    router && router.options.parseQuery
+  );
+
+  var hash = next.hash || parsedPath.hash;
+  if (hash && hash.charAt(0) !== '#') {
+    hash = "#" + hash;
+  }
+
+  return {
+    _normalized: true,
+    path: path,
+    query: query,
+    hash: hash
+  }
+}
+
+function assign (a, b) {
+  for (var key in b) {
+    a[key] = b[key];
+  }
+  return a
+}
+
+/*  */
+
+
+function createMatcher (
+  routes,
+  router
+) {
+  var ref = createRouteMap(routes);
+  var pathList = ref.pathList;
+  var pathMap = ref.pathMap;
+  var nameMap = ref.nameMap;
+
+  function addRoutes (routes) {
+    createRouteMap(routes, pathList, pathMap, nameMap);
+  }
+
+  function match (
+    raw,
+    currentRoute,
+    redirectedFrom
+  ) {
+    var location = normalizeLocation(raw, currentRoute, false, router);
+    var name = location.name;
+
+    if (name) {
+      var record = nameMap[name];
+      {
+        warn(record, ("Route with name '" + name + "' does not exist"));
+      }
+      if (!record) { return _createRoute(null, location) }
+      var paramNames = record.regex.keys
+        .filter(function (key) { return !key.optional; })
+        .map(function (key) { return key.name; });
+
+      if (typeof location.params !== 'object') {
+        location.params = {};
+      }
+
+      if (currentRoute && typeof currentRoute.params === 'object') {
+        for (var key in currentRoute.params) {
+          if (!(key in location.params) && paramNames.indexOf(key) > -1) {
+            location.params[key] = currentRoute.params[key];
+          }
+        }
+      }
+
+      if (record) {
+        location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""));
+        return _createRoute(record, location, redirectedFrom)
+      }
+    } else if (location.path) {
+      location.params = {};
+      for (var i = 0; i < pathList.length; i++) {
+        var path = pathList[i];
+        var record$1 = pathMap[path];
+        if (matchRoute(record$1.regex, location.path, location.params)) {
+          return _createRoute(record$1, location, redirectedFrom)
+        }
+      }
+    }
+    // no match
+    return _createRoute(null, location)
+  }
+
+  function redirect (
+    record,
+    location
+  ) {
+    var originalRedirect = record.redirect;
+    var redirect = typeof originalRedirect === 'function'
+        ? originalRedirect(createRoute(record, location, null, router))
+        : originalRedirect;
+
+    if (typeof redirect === 'string') {
+      redirect = { path: redirect };
+    }
+
+    if (!redirect || typeof redirect !== 'object') {
+      {
+        warn(
+          false, ("invalid redirect option: " + (JSON.stringify(redirect)))
+        );
+      }
+      return _createRoute(null, location)
+    }
+
+    var re = redirect;
+    var name = re.name;
+    var path = re.path;
+    var query = location.query;
+    var hash = location.hash;
+    var params = location.params;
+    query = re.hasOwnProperty('query') ? re.query : query;
+    hash = re.hasOwnProperty('hash') ? re.hash : hash;
+    params = re.hasOwnProperty('params') ? re.params : params;
+
+    if (name) {
+      // resolved named direct
+      var targetRecord = nameMap[name];
+      {
+        assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."));
+      }
+      return match({
+        _normalized: true,
+        name: name,
+        query: query,
+        hash: hash,
+        params: params
+      }, undefined, location)
+    } else if (path) {
+      // 1. resolve relative redirect
+      var rawPath = resolveRecordPath(path, record);
+      // 2. resolve params
+      var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""));
+      // 3. rematch with existing query and hash
+      return match({
+        _normalized: true,
+        path: resolvedPath,
+        query: query,
+        hash: hash
+      }, undefined, location)
+    } else {
+      {
+        warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))));
+      }
+      return _createRoute(null, location)
+    }
+  }
+
+  function alias (
+    record,
+    location,
+    matchAs
+  ) {
+    var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""));
+    var aliasedMatch = match({
+      _normalized: true,
+      path: aliasedPath
+    });
+    if (aliasedMatch) {
+      var matched = aliasedMatch.matched;
+      var aliasedRecord = matched[matched.length - 1];
+      location.params = aliasedMatch.params;
+      return _createRoute(aliasedRecord, location)
+    }
+    return _createRoute(null, location)
+  }
+
+  function _createRoute (
+    record,
+    location,
+    redirectedFrom
+  ) {
+    if (record && record.redirect) {
+      return redirect(record, redirectedFrom || location)
+    }
+    if (record && record.matchAs) {
+      return alias(record, location, record.matchAs)
+    }
+    return createRoute(record, location, redirectedFrom, router)
+  }
+
+  return {
+    match: match,
+    addRoutes: addRoutes
+  }
+}
+
+function matchRoute (
+  regex,
+  path,
+  params
+) {
+  var m = path.match(regex);
+
+  if (!m) {
+    return false
+  } else if (!params) {
+    return true
+  }
+
+  for (var i = 1, len = m.length; i < len; ++i) {
+    var key = regex.keys[i - 1];
+    var val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];
+    if (key) {
+      params[key.name] = val;
+    }
+  }
+
+  return true
+}
+
+function resolveRecordPath (path, record) {
+  return resolvePath(path, record.parent ? record.parent.path : '/', true)
+}
+
+/*  */
+
+
+var positionStore = Object.create(null);
+
+function setupScroll () {
+  // Fix for #1585 for Firefox
+  window.history.replaceState({ key: getStateKey() }, '');
+  window.addEventListener('popstate', function (e) {
+    saveScrollPosition();
+    if (e.state && e.state.key) {
+      setStateKey(e.state.key);
+    }
+  });
+}
+
+function handleScroll (
+  router,
+  to,
+  from,
+  isPop
+) {
+  if (!router.app) {
+    return
+  }
+
+  var behavior = router.options.scrollBehavior;
+  if (!behavior) {
+    return
+  }
+
+  {
+    assert(typeof behavior === 'function', "scrollBehavior must be a function");
+  }
+
+  // wait until re-render finishes before scrolling
+  router.app.$nextTick(function () {
+    var position = getScrollPosition();
+    var shouldScroll = behavior(to, from, isPop ? position : null);
+
+    if (!shouldScroll) {
+      return
+    }
+
+    if (typeof shouldScroll.then === 'function') {
+      shouldScroll.then(function (shouldScroll) {
+        scrollToPosition((shouldScroll), position);
+      }).catch(function (err) {
+        {
+          assert(false, err.toString());
+        }
+      });
+    } else {
+      scrollToPosition(shouldScroll, position);
+    }
+  });
+}
+
+function saveScrollPosition () {
+  var key = getStateKey();
+  if (key) {
+    positionStore[key] = {
+      x: window.pageXOffset,
+      y: window.pageYOffset
+    };
+  }
+}
+
+function getScrollPosition () {
+  var key = getStateKey();
+  if (key) {
+    return positionStore[key]
+  }
+}
+
+function getElementPosition (el, offset) {
+  var docEl = document.documentElement;
+  var docRect = docEl.getBoundingClientRect();
+  var elRect = el.getBoundingClientRect();
+  return {
+    x: elRect.left - docRect.left - offset.x,
+    y: elRect.top - docRect.top - offset.y
+  }
+}
+
+function isValidPosition (obj) {
+  return isNumber(obj.x) || isNumber(obj.y)
+}
+
+function normalizePosition (obj) {
+  return {
+    x: isNumber(obj.x) ? obj.x : window.pageXOffset,
+    y: isNumber(obj.y) ? obj.y : window.pageYOffset
+  }
+}
+
+function normalizeOffset (obj) {
+  return {
+    x: isNumber(obj.x) ? obj.x : 0,
+    y: isNumber(obj.y) ? obj.y : 0
+  }
+}
+
+function isNumber (v) {
+  return typeof v === 'number'
+}
+
+function scrollToPosition (shouldScroll, position) {
+  var isObject = typeof shouldScroll === 'object';
+  if (isObject && typeof shouldScroll.selector === 'string') {
+    var el = document.querySelector(shouldScroll.selector);
+    if (el) {
+      var offset = shouldScroll.offset && typeof shouldScroll.offset === 'object' ? shouldScroll.offset : {};
+      offset = normalizeOffset(offset);
+      position = getElementPosition(el, offset);
+    } else if (isValidPosition(shouldScroll)) {
+      position = normalizePosition(shouldScroll);
+    }
+  } else if (isObject && isValidPosition(shouldScroll)) {
+    position = normalizePosition(shouldScroll);
+  }
+
+  if (position) {
+    window.scrollTo(position.x, position.y);
+  }
+}
+
+/*  */
+
+var supportsPushState = inBrowser && (function () {
+  var ua = window.navigator.userAgent;
+
+  if (
+    (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
+    ua.indexOf('Mobile Safari') !== -1 &&
+    ua.indexOf('Chrome') === -1 &&
+    ua.indexOf('Windows Phone') === -1
+  ) {
+    return false
+  }
+
+  return window.history && 'pushState' in window.history
+})();
+
+// use User Timing api (if present) for more accurate key precision
+var Time = inBrowser && window.performance && window.performance.now
+  ? window.performance
+  : Date;
+
+var _key = genKey();
+
+function genKey () {
+  return Time.now().toFixed(3)
+}
+
+function getStateKey () {
+  return _key
+}
+
+function setStateKey (key) {
+  _key = key;
+}
+
+function pushState (url, replace) {
+  saveScrollPosition();
+  // try...catch the pushState call to get around Safari
+  // DOM Exception 18 where it limits to 100 pushState calls
+  var history = window.history;
+  try {
+    if (replace) {
+      history.replaceState({ key: _key }, '', url);
+    } else {
+      _key = genKey();
+      history.pushState({ key: _key }, '', url);
+    }
+  } catch (e) {
+    window.location[replace ? 'replace' : 'assign'](url);
+  }
+}
+
+function replaceState (url) {
+  pushState(url, true);
+}
+
+/*  */
+
+function runQueue (queue, fn, cb) {
+  var step = function (index) {
+    if (index >= queue.length) {
+      cb();
+    } else {
+      if (queue[index]) {
+        fn(queue[index], function () {
+          step(index + 1);
+        });
+      } else {
+        step(index + 1);
+      }
+    }
+  };
+  step(0);
+}
+
+/*  */
+
+function resolveAsyncComponents (matched) {
+  return function (to, from, next) {
+    var hasAsync = false;
+    var pending = 0;
+    var error = null;
+
+    flatMapComponents(matched, function (def, _, match, key) {
+      // if it's a function and doesn't have cid attached,
+      // assume it's an async component resolve function.
+      // we are not using Vue's default async resolving mechanism because
+      // we want to halt the navigation until the incoming component has been
+      // resolved.
+      if (typeof def === 'function' && def.cid === undefined) {
+        hasAsync = true;
+        pending++;
+
+        var resolve = once(function (resolvedDef) {
+          if (isESModule(resolvedDef)) {
+            resolvedDef = resolvedDef.default;
+          }
+          // save resolved on async factory in case it's used elsewhere
+          def.resolved = typeof resolvedDef === 'function'
+            ? resolvedDef
+            : _Vue.extend(resolvedDef);
+          match.components[key] = resolvedDef;
+          pending--;
+          if (pending <= 0) {
+            next();
+          }
+        });
+
+        var reject = once(function (reason) {
+          var msg = "Failed to resolve async component " + key + ": " + reason;
+          "development" !== 'production' && warn(false, msg);
+          if (!error) {
+            error = isError(reason)
+              ? reason
+              : new Error(msg);
+            next(error);
+          }
+        });
+
+        var res;
+        try {
+          res = def(resolve, reject);
+        } catch (e) {
+          reject(e);
+        }
+        if (res) {
+          if (typeof res.then === 'function') {
+            res.then(resolve, reject);
+          } else {
+            // new syntax in Vue 2.3
+            var comp = res.component;
+            if (comp && typeof comp.then === 'function') {
+              comp.then(resolve, reject);
+            }
+          }
+        }
+      }
+    });
+
+    if (!hasAsync) { next(); }
+  }
+}
+
+function flatMapComponents (
+  matched,
+  fn
+) {
+  return flatten(matched.map(function (m) {
+    return Object.keys(m.components).map(function (key) { return fn(
+      m.components[key],
+      m.instances[key],
+      m, key
+    ); })
+  }))
+}
+
+function flatten (arr) {
+  return Array.prototype.concat.apply([], arr)
+}
+
+var hasSymbol =
+  typeof Symbol === 'function' &&
+  typeof Symbol.toStringTag === 'symbol';
+
+function isESModule (obj) {
+  return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
+}
+
+// in Webpack 2, require.ensure now also returns a Promise
+// so the resolve/reject functions may get called an extra time
+// if the user uses an arrow function shorthand that happens to
+// return that Promise.
+function once (fn) {
+  var called = false;
+  return function () {
+    var args = [], len = arguments.length;
+    while ( len-- ) args[ len ] = arguments[ len ];
+
+    if (called) { return }
+    called = true;
+    return fn.apply(this, args)
+  }
+}
+
+/*  */
+
+var History = function History (router, base) {
+  this.router = router;
+  this.base = normalizeBase(base);
+  // start with a route object that stands for "nowhere"
+  this.current = START;
+  this.pending = null;
+  this.ready = false;
+  this.readyCbs = [];
+  this.readyErrorCbs = [];
+  this.errorCbs = [];
+};
+
+History.prototype.listen = function listen (cb) {
+  this.cb = cb;
+};
+
+History.prototype.onReady = function onReady (cb, errorCb) {
+  if (this.ready) {
+    cb();
+  } else {
+    this.readyCbs.push(cb);
+    if (errorCb) {
+      this.readyErrorCbs.push(errorCb);
+    }
+  }
+};
+
+History.prototype.onError = function onError (errorCb) {
+  this.errorCbs.push(errorCb);
+};
+
+History.prototype.transitionTo = function transitionTo (location, onComplete, onAbort) {
+    var this$1 = this;
+
+  var route = this.router.match(location, this.current);
+  this.confirmTransition(route, function () {
+    this$1.updateRoute(route);
+    onComplete && onComplete(route);
+    this$1.ensureURL();
+
+    // fire ready cbs once
+    if (!this$1.ready) {
+      this$1.ready = true;
+      this$1.readyCbs.forEach(function (cb) { cb(route); });
+    }
+  }, function (err) {
+    if (onAbort) {
+      onAbort(err);
+    }
+    if (err && !this$1.ready) {
+      this$1.ready = true;
+      this$1.readyErrorCbs.forEach(function (cb) { cb(err); });
+    }
+  });
+};
+
+History.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {
+    var this$1 = this;
+
+  var current = this.current;
+  var abort = function (err) {
+    if (isError(err)) {
+      if (this$1.errorCbs.length) {
+        this$1.errorCbs.forEach(function (cb) { cb(err); });
+      } else {
+        warn(false, 'uncaught error during route navigation:');
+        console.error(err);
+      }
+    }
+    onAbort && onAbort(err);
+  };
+  if (
+    isSameRoute(route, current) &&
+    // in the case the route map has been dynamically appended to
+    route.matched.length === current.matched.length
+  ) {
+    this.ensureURL();
+    return abort()
+  }
+
+  var ref = resolveQueue(this.current.matched, route.matched);
+    var updated = ref.updated;
+    var deactivated = ref.deactivated;
+    var activated = ref.activated;
+
+  var queue = [].concat(
+    // in-component leave guards
+    extractLeaveGuards(deactivated),
+    // global before hooks
+    this.router.beforeHooks,
+    // in-component update hooks
+    extractUpdateHooks(updated),
+    // in-config enter guards
+    activated.map(function (m) { return m.beforeEnter; }),
+    // async components
+    resolveAsyncComponents(activated)
+  );
+
+  this.pending = route;
+  var iterator = function (hook, next) {
+    if (this$1.pending !== route) {
+      return abort()
+    }
+    try {
+      hook(route, current, function (to) {
+        if (to === false || isError(to)) {
+          // next(false) -> abort navigation, ensure current URL
+          this$1.ensureURL(true);
+          abort(to);
+        } else if (
+          typeof to === 'string' ||
+          (typeof to === 'object' && (
+            typeof to.path === 'string' ||
+            typeof to.name === 'string'
+          ))
+        ) {
+          // next('/') or next({ path: '/' }) -> redirect
+          abort();
+          if (typeof to === 'object' && to.replace) {
+            this$1.replace(to);
+          } else {
+            this$1.push(to);
+          }
+        } else {
+          // confirm transition and pass on the value
+          next(to);
+        }
+      });
+    } catch (e) {
+      abort(e);
+    }
+  };
+
+  runQueue(queue, iterator, function () {
+    var postEnterCbs = [];
+    var isValid = function () { return this$1.current === route; };
+    // wait until async components are resolved before
+    // extracting in-component enter guards
+    var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
+    var queue = enterGuards.concat(this$1.router.resolveHooks);
+    runQueue(queue, iterator, function () {
+      if (this$1.pending !== route) {
+        return abort()
+      }
+      this$1.pending = null;
+      onComplete(route);
+      if (this$1.router.app) {
+        this$1.router.app.$nextTick(function () {
+          postEnterCbs.forEach(function (cb) { cb(); });
+        });
+      }
+    });
+  });
+};
+
+History.prototype.updateRoute = function updateRoute (route) {
+  var prev = this.current;
+  this.current = route;
+  this.cb && this.cb(route);
+  this.router.afterHooks.forEach(function (hook) {
+    hook && hook(route, prev);
+  });
+};
+
+function normalizeBase (base) {
+  if (!base) {
+    if (inBrowser) {
+      // respect <base> tag
+      var baseEl = document.querySelector('base');
+      base = (baseEl && baseEl.getAttribute('href')) || '/';
+      // strip full URL origin
+      base = base.replace(/^https?:\/\/[^\/]+/, '');
+    } else {
+      base = '/';
+    }
+  }
+  // make sure there's the starting slash
+  if (base.charAt(0) !== '/') {
+    base = '/' + base;
+  }
+  // remove trailing slash
+  return base.replace(/\/$/, '')
+}
+
+function resolveQueue (
+  current,
+  next
+) {
+  var i;
+  var max = Math.max(current.length, next.length);
+  for (i = 0; i < max; i++) {
+    if (current[i] !== next[i]) {
+      break
+    }
+  }
+  return {
+    updated: next.slice(0, i),
+    activated: next.slice(i),
+    deactivated: current.slice(i)
+  }
+}
+
+function extractGuards (
+  records,
+  name,
+  bind,
+  reverse
+) {
+  var guards = flatMapComponents(records, function (def, instance, match, key) {
+    var guard = extractGuard(def, name);
+    if (guard) {
+      return Array.isArray(guard)
+        ? guard.map(function (guard) { return bind(guard, instance, match, key); })
+        : bind(guard, instance, match, key)
+    }
+  });
+  return flatten(reverse ? guards.reverse() : guards)
+}
+
+function extractGuard (
+  def,
+  key
+) {
+  if (typeof def !== 'function') {
+    // extend now so that global mixins are applied.
+    def = _Vue.extend(def);
+  }
+  return def.options[key]
+}
+
+function extractLeaveGuards (deactivated) {
+  return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
+}
+
+function extractUpdateHooks (updated) {
+  return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
+}
+
+function bindGuard (guard, instance) {
+  if (instance) {
+    return function boundRouteGuard () {
+      return guard.apply(instance, arguments)
+    }
+  }
+}
+
+function extractEnterGuards (
+  activated,
+  cbs,
+  isValid
+) {
+  return extractGuards(activated, 'beforeRouteEnter', function (guard, _, match, key) {
+    return bindEnterGuard(guard, match, key, cbs, isValid)
+  })
+}
+
+function bindEnterGuard (
+  guard,
+  match,
+  key,
+  cbs,
+  isValid
+) {
+  return function routeEnterGuard (to, from, next) {
+    return guard(to, from, function (cb) {
+      next(cb);
+      if (typeof cb === 'function') {
+        cbs.push(function () {
+          // #750
+          // if a router-view is wrapped with an out-in transition,
+          // the instance may not have been registered at this time.
+          // we will need to poll for registration until current route
+          // is no longer valid.
+          poll(cb, match.instances, key, isValid);
+        });
+      }
+    })
+  }
+}
+
+function poll (
+  cb, // somehow flow cannot infer this is a function
+  instances,
+  key,
+  isValid
+) {
+  if (instances[key]) {
+    cb(instances[key]);
+  } else if (isValid()) {
+    setTimeout(function () {
+      poll(cb, instances, key, isValid);
+    }, 16);
+  }
+}
+
+/*  */
+
+
+var HTML5History = (function (History$$1) {
+  function HTML5History (router, base) {
+    var this$1 = this;
+
+    History$$1.call(this, router, base);
+
+    var expectScroll = router.options.scrollBehavior;
+
+    if (expectScroll) {
+      setupScroll();
+    }
+
+    var initLocation = getLocation(this.base);
+    window.addEventListener('popstate', function (e) {
+      var current = this$1.current;
+
+      // Avoiding first `popstate` event dispatched in some browsers but first
+      // history route not updated since async guard at the same time.
+      var location = getLocation(this$1.base);
+      if (this$1.current === START && location === initLocation) {
+        return
+      }
+
+      this$1.transitionTo(location, function (route) {
+        if (expectScroll) {
+          handleScroll(router, route, current, true);
+        }
+      });
+    });
+  }
+
+  if ( History$$1 ) HTML5History.__proto__ = History$$1;
+  HTML5History.prototype = Object.create( History$$1 && History$$1.prototype );
+  HTML5History.prototype.constructor = HTML5History;
+
+  HTML5History.prototype.go = function go (n) {
+    window.history.go(n);
+  };
+
+  HTML5History.prototype.push = function push (location, onComplete, onAbort) {
+    var this$1 = this;
+
+    var ref = this;
+    var fromRoute = ref.current;
+    this.transitionTo(location, function (route) {
+      pushState(cleanPath(this$1.base + route.fullPath));
+      handleScroll(this$1.router, route, fromRoute, false);
+      onComplete && onComplete(route);
+    }, onAbort);
+  };
+
+  HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {
+    var this$1 = this;
+
+    var ref = this;
+    var fromRoute = ref.current;
+    this.transitionTo(location, function (route) {
+      replaceState(cleanPath(this$1.base + route.fullPath));
+      handleScroll(this$1.router, route, fromRoute, false);
+      onComplete && onComplete(route);
+    }, onAbort);
+  };
+
+  HTML5History.prototype.ensureURL = function ensureURL (push) {
+    if (getLocation(this.base) !== this.current.fullPath) {
+      var current = cleanPath(this.base + this.current.fullPath);
+      push ? pushState(current) : replaceState(current);
+    }
+  };
+
+  HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {
+    return getLocation(this.base)
+  };
+
+  return HTML5History;
+}(History));
+
+function getLocation (base) {
+  var path = window.location.pathname;
+  if (base && path.indexOf(base) === 0) {
+    path = path.slice(base.length);
+  }
+  return (path || '/') + window.location.search + window.location.hash
+}
+
+/*  */
+
+
+var HashHistory = (function (History$$1) {
+  function HashHistory (router, base, fallback) {
+    History$$1.call(this, router, base);
+    // check history fallback deeplinking
+    if (fallback && checkFallback(this.base)) {
+      return
+    }
+    ensureSlash();
+  }
+
+  if ( History$$1 ) HashHistory.__proto__ = History$$1;
+  HashHistory.prototype = Object.create( History$$1 && History$$1.prototype );
+  HashHistory.prototype.constructor = HashHistory;
+
+  // this is delayed until the app mounts
+  // to avoid the hashchange listener being fired too early
+  HashHistory.prototype.setupListeners = function setupListeners () {
+    var this$1 = this;
+
+    var router = this.router;
+    var expectScroll = router.options.scrollBehavior;
+    var supportsScroll = supportsPushState && expectScroll;
+
+    if (supportsScroll) {
+      setupScroll();
+    }
+
+    window.addEventListener(supportsPushState ? 'popstate' : 'hashchange', function () {
+      var current = this$1.current;
+      if (!ensureSlash()) {
+        return
+      }
+      this$1.transitionTo(getHash(), function (route) {
+        if (supportsScroll) {
+          handleScroll(this$1.router, route, current, true);
+        }
+        if (!supportsPushState) {
+          replaceHash(route.fullPath);
+        }
+      });
+    });
+  };
+
+  HashHistory.prototype.push = function push (location, onComplete, onAbort) {
+    var this$1 = this;
+
+    var ref = this;
+    var fromRoute = ref.current;
+    this.transitionTo(location, function (route) {
+      pushHash(route.fullPath);
+      handleScroll(this$1.router, route, fromRoute, false);
+      onComplete && onComplete(route);
+    }, onAbort);
+  };
+
+  HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {
+    var this$1 = this;
+
+    var ref = this;
+    var fromRoute = ref.current;
+    this.transitionTo(location, function (route) {
+      replaceHash(route.fullPath);
+      handleScroll(this$1.router, route, fromRoute, false);
+      onComplete && onComplete(route);
+    }, onAbort);
+  };
+
+  HashHistory.prototype.go = function go (n) {
+    window.history.go(n);
+  };
+
+  HashHistory.prototype.ensureURL = function ensureURL (push) {
+    var current = this.current.fullPath;
+    if (getHash() !== current) {
+      push ? pushHash(current) : replaceHash(current);
+    }
+  };
+
+  HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {
+    return getHash()
+  };
+
+  return HashHistory;
+}(History));
+
+function checkFallback (base) {
+  var location = getLocation(base);
+  if (!/^\/#/.test(location)) {
+    window.location.replace(
+      cleanPath(base + '/#' + location)
+    );
+    return true
+  }
+}
+
+function ensureSlash () {
+  var path = getHash();
+  if (path.charAt(0) === '/') {
+    return true
+  }
+  replaceHash('/' + path);
+  return false
+}
+
+function getHash () {
+  // We can't use window.location.hash here because it's not
+  // consistent across browsers - Firefox will pre-decode it!
+  var href = window.location.href;
+  var index = href.indexOf('#');
+  return index === -1 ? '' : href.slice(index + 1)
+}
+
+function getUrl (path) {
+  var href = window.location.href;
+  var i = href.indexOf('#');
+  var base = i >= 0 ? href.slice(0, i) : href;
+  return (base + "#" + path)
+}
+
+function pushHash (path) {
+  if (supportsPushState) {
+    pushState(getUrl(path));
+  } else {
+    window.location.hash = path;
+  }
+}
+
+function replaceHash (path) {
+  if (supportsPushState) {
+    replaceState(getUrl(path));
+  } else {
+    window.location.replace(getUrl(path));
+  }
+}
+
+/*  */
+
+
+var AbstractHistory = (function (History$$1) {
+  function AbstractHistory (router, base) {
+    History$$1.call(this, router, base);
+    this.stack = [];
+    this.index = -1;
+  }
+
+  if ( History$$1 ) AbstractHistory.__proto__ = History$$1;
+  AbstractHistory.prototype = Object.create( History$$1 && History$$1.prototype );
+  AbstractHistory.prototype.constructor = AbstractHistory;
+
+  AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {
+    var this$1 = this;
+
+    this.transitionTo(location, function (route) {
+      this$1.stack = this$1.stack.slice(0, this$1.index + 1).concat(route);
+      this$1.index++;
+      onComplete && onComplete(route);
+    }, onAbort);
+  };
+
+  AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {
+    var this$1 = this;
+
+    this.transitionTo(location, function (route) {
+      this$1.stack = this$1.stack.slice(0, this$1.index).concat(route);
+      onComplete && onComplete(route);
+    }, onAbort);
+  };
+
+  AbstractHistory.prototype.go = function go (n) {
+    var this$1 = this;
+
+    var targetIndex = this.index + n;
+    if (targetIndex < 0 || targetIndex >= this.stack.length) {
+      return
+    }
+    var route = this.stack[targetIndex];
+    this.confirmTransition(route, function () {
+      this$1.index = targetIndex;
+      this$1.updateRoute(route);
+    });
+  };
+
+  AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {
+    var current = this.stack[this.stack.length - 1];
+    return current ? current.fullPath : '/'
+  };
+
+  AbstractHistory.prototype.ensureURL = function ensureURL () {
+    // noop
+  };
+
+  return AbstractHistory;
+}(History));
+
+/*  */
+
+var VueRouter = function VueRouter (options) {
+  if ( options === void 0 ) options = {};
+
+  this.app = null;
+  this.apps = [];
+  this.options = options;
+  this.beforeHooks = [];
+  this.resolveHooks = [];
+  this.afterHooks = [];
+  this.matcher = createMatcher(options.routes || [], this);
+
+  var mode = options.mode || 'hash';
+  this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false;
+  if (this.fallback) {
+    mode = 'hash';
+  }
+  if (!inBrowser) {
+    mode = 'abstract';
+  }
+  this.mode = mode;
+
+  switch (mode) {
+    case 'history':
+      this.history = new HTML5History(this, options.base);
+      break
+    case 'hash':
+      this.history = new HashHistory(this, options.base, this.fallback);
+      break
+    case 'abstract':
+      this.history = new AbstractHistory(this, options.base);
+      break
+    default:
+      {
+        assert(false, ("invalid mode: " + mode));
+      }
+  }
+};
+
+var prototypeAccessors = { currentRoute: { configurable: true } };
+
+VueRouter.prototype.match = function match (
+  raw,
+  current,
+  redirectedFrom
+) {
+  return this.matcher.match(raw, current, redirectedFrom)
+};
+
+prototypeAccessors.currentRoute.get = function () {
+  return this.history && this.history.current
+};
+
+VueRouter.prototype.init = function init (app /* Vue component instance */) {
+    var this$1 = this;
+
+  "development" !== 'production' && assert(
+    install.installed,
+    "not installed. Make sure to call `Vue.use(VueRouter)` " +
+    "before creating root instance."
+  );
+
+  this.apps.push(app);
+
+  // main app already initialized.
+  if (this.app) {
+    return
+  }
+
+  this.app = app;
+
+  var history = this.history;
+
+  if (history instanceof HTML5History) {
+    history.transitionTo(history.getCurrentLocation());
+  } else if (history instanceof HashHistory) {
+    var setupHashListener = function () {
+      history.setupListeners();
+    };
+    history.transitionTo(
+      history.getCurrentLocation(),
+      setupHashListener,
+      setupHashListener
+    );
+  }
+
+  history.listen(function (route) {
+    this$1.apps.forEach(function (app) {
+      app._route = route;
+    });
+  });
+};
+
+VueRouter.prototype.beforeEach = function beforeEach (fn) {
+  return registerHook(this.beforeHooks, fn)
+};
+
+VueRouter.prototype.beforeResolve = function beforeResolve (fn) {
+  return registerHook(this.resolveHooks, fn)
+};
+
+VueRouter.prototype.afterEach = function afterEach (fn) {
+  return registerHook(this.afterHooks, fn)
+};
+
+VueRouter.prototype.onReady = function onReady (cb, errorCb) {
+  this.history.onReady(cb, errorCb);
+};
+
+VueRouter.prototype.onError = function onError (errorCb) {
+  this.history.onError(errorCb);
+};
+
+VueRouter.prototype.push = function push (location, onComplete, onAbort) {
+  this.history.push(location, onComplete, onAbort);
+};
+
+VueRouter.prototype.replace = function replace (location, onComplete, onAbort) {
+  this.history.replace(location, onComplete, onAbort);
+};
+
+VueRouter.prototype.go = function go (n) {
+  this.history.go(n);
+};
+
+VueRouter.prototype.back = function back () {
+  this.go(-1);
+};
+
+VueRouter.prototype.forward = function forward () {
+  this.go(1);
+};
+
+VueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {
+  var route = to
+    ? to.matched
+      ? to
+      : this.resolve(to).route
+    : this.currentRoute;
+  if (!route) {
+    return []
+  }
+  return [].concat.apply([], route.matched.map(function (m) {
+    return Object.keys(m.components).map(function (key) {
+      return m.components[key]
+    })
+  }))
+};
+
+VueRouter.prototype.resolve = function resolve (
+  to,
+  current,
+  append
+) {
+  var location = normalizeLocation(
+    to,
+    current || this.history.current,
+    append,
+    this
+  );
+  var route = this.match(location, current);
+  var fullPath = route.redirectedFrom || route.fullPath;
+  var base = this.history.base;
+  var href = createHref(base, fullPath, this.mode);
+  return {
+    location: location,
+    route: route,
+    href: href,
+    // for backwards compat
+    normalizedTo: location,
+    resolved: route
+  }
+};
+
+VueRouter.prototype.addRoutes = function addRoutes (routes) {
+  this.matcher.addRoutes(routes);
+  if (this.history.current !== START) {
+    this.history.transitionTo(this.history.getCurrentLocation());
+  }
+};
+
+Object.defineProperties( VueRouter.prototype, prototypeAccessors );
+
+function registerHook (list, fn) {
+  list.push(fn);
+  return function () {
+    var i = list.indexOf(fn);
+    if (i > -1) { list.splice(i, 1); }
+  }
+}
+
+function createHref (base, fullPath, mode) {
+  var path = mode === 'hash' ? '#' + fullPath : fullPath;
+  return base ? cleanPath(base + '/' + path) : path
+}
+
+VueRouter.install = install;
+VueRouter.version = '3.0.1';
+
+if (inBrowser && window.Vue) {
+  window.Vue.use(VueRouter);
+}
+
+return VueRouter;
+
+})));

File diff suppressed because it is too large
+ 0 - 0
Basic/js/vue-swipe.js


File diff suppressed because it is too large
+ 5 - 0
Basic/js/vue.min.js


+ 9 - 0
Basic/vuex/session.html

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="UTF-8">
+		<title></title>
+	</head>
+	<body>
+	</body>
+</html>

+ 9 - 0
Basic/vuex/storage.html

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="UTF-8">
+		<title></title>
+	</head>
+	<body>
+	</body>
+</html>

+ 57 - 0
Basic/vuex/vuex.html

@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+
+	<head>
+		<meta charset="utf-8">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+		<title>vuex</title>
+		<meta name="description" content="">
+		<meta name="keywords" content="">
+		<link href="" rel="stylesheet">
+		<script src="../js/vue.min.js"></script>
+		<script src="//cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>
+		<script src="//unpkg.com/vuex@3.1.0/dist/vuex.js"></script>
+	</head>
+
+	<body>
+		<div id="app">
+			<p>{{ count }}</p>
+			<p>
+				<button @click="increment">+</button>
+				<button @click="decrement">-</button>
+			</p>
+		</div>
+
+	</body>
+	<script type="text/javascript">
+		// make sure to call Vue.use(Vuex) if using a module system
+
+		const store = new Vuex.Store({
+			state: {
+				count: 0
+			},
+			mutations: {
+				increment: state => state.count++,
+				decrement: state => state.count--
+			}
+		})
+
+		new Vue({
+			el: '#app',
+			computed: {
+				count: function() {
+					return store.state.count;
+				}
+			},
+			methods: {
+				increment: function() {
+					store.commit('increment');
+				},
+				decrement: function() {
+					store.commit('decrement');
+				}
+			}
+		})
+	</script>
+
+</html>

+ 7 - 0
Basic/监听属性/watch2.html

@@ -19,6 +19,13 @@
 				el: '#app',
 				data: {
 					counter: 1
+				},
+				watch: {
+					searchQuery: function(query) {
+						this.isSearch = false;
+						this.items.push(query);
+					}
+
 				}
 			});
 			vm.$watch('counter', function(nval, oval) {

+ 72 - 0
Basic/组件/子组件之间传递数据.html

@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+
+	<head>
+		<meta charset="utf-8">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+		<title>子组件之间传递数据</title>
+		<meta name="description" content="">
+		<meta name="keywords" content="">
+		<link href="" rel="stylesheet">
+		<script type="text/javascript" src='../js/vue.min.js'></script>
+	</head>
+
+	<body>
+		<div id='app'>
+			<foo>组件1</foo>
+			<hr>
+			<bar>组件2</bar>
+		</div>
+		<script type="text/javascript">
+			//利用 eventBus 作为一个中间中转站,去实现兄弟之间的通信
+			var eventBus = new Vue({});
+			var foo = {
+				template: `<button @click='addBar'>{{fooCount}}</button>`,
+				data() {
+					return {
+						fooCount: 0
+					}
+				},
+				methods: {
+					addBar: function() {
+						eventBus.$emit('addBar')
+					}
+				},
+				mounted() {
+					//再次借用了eventBus
+					eventBus.$on('addFoo', function() {
+						this.fooCount++
+					}.bind(this))
+				}
+			}
+			var bar = {
+				template: `<button @click='addFoo'>{{barCount}}</button>`,
+				data: function() {
+					return {
+						barCount: 0
+					}
+				},
+				methods: {
+					addFoo: function() {
+						console.log(eventBus);
+						eventBus.$emit('addFoo')
+					}
+				},
+				mounted() {
+					eventBus.$on('addBar', function() {
+						this.barCount++
+					}.bind(this))
+				}
+			}
+			new Vue({
+				el: '#app',
+				components: {
+					foo,
+					bar
+				}
+
+			})
+		</script>
+	</body>
+
+</html>

+ 3 - 1
Basic/网络/ajax_info.txt

@@ -1 +1,3 @@
-AJAX 是与服务器交换数据并更新部分网页的技术,在不重新加载整个页面的情况下 
+Ajax info.txt
+
+下面是数据,xxxxxxxxxxxxxx

+ 40 - 0
Basic/网络/axios请求数据.html

@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+
+	<head>
+		<meta charset="utf-8">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+		<title>axios 获取数据</title>
+		<meta name="description" content="">
+		<meta name="keywords" content="">
+		<link href="" rel="stylesheet">
+	</head>
+
+	<body>
+		<div id="app">
+			<button @click='getAjaxInfo()'>按钮</button>
+			<span> {{msg}}</span>
+		</div>
+		<script type="text/javascript" src='../js/vue.min.js'></script>
+		<script type="text/javascript" src='../js/axios.min.js'></script>
+		<script type="text/javascript">
+			//没有后台数据,所以会报错
+			var app = new Vue({
+				el: '#app',
+				data: {
+					msg: '我是数据'
+				},
+				methods: {
+					getAjaxInfo: function() {
+						axios('ajax_info.txt').then(function(res) {
+							this.msg = res.data;
+						}.bind(this)).catch(function(err) {
+							console.log(err);
+						})
+					}
+				}
+			});
+		</script>
+	</body>
+
+</html>

+ 36 - 0
Basic/表单/标签.html

@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="zh">
+
+	<head>
+		<title></title>
+		<meta charset="UTF-8">
+		<meta name="viewport" content="width=device-width, initial-scale=1">
+		<script src="https://unpkg.com/vue/dist/vue.js"></script>
+		<link href="../css/style.css" rel="stylesheet"> </head>
+
+	<body>
+		<div id="myApp">
+			<a v-link="'/about'" target="_blank">About</a>
+			<router-link to="/about">About</router-link>
+			<div>
+				<li v-link-active>
+					<a v-link="'/about'">About</a>
+				</li>
+			</div>
+		</div>
+
+		<script>
+			Vue.component('say-hello', {
+				props: ['pname'],
+				template: '<div>你好,<strong>{{pname}}</strong>!</div>',
+			});
+			var myApp = new Vue({
+				el: '#myApp',
+				data: {
+					myname: 'Koma'
+				}
+			});
+		</script>
+	</body>
+
+</html>

+ 67 - 55
Basic/路由/index.html

@@ -1,58 +1,70 @@
 <!DOCTYPE html>
 <html>
-<head>
-<meta charset="utf-8">
-<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
-<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
-<script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.min.js"></script>
-</head>
-<body>
-<div id="app">
-  <h1>Hello App!</h1>
-  <p>
-    <!-- 使用 router-link 组件来导航. -->
-    <!-- 通过传入 `to` 属性指定链接. -->
-    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
-    <router-link to="/foo">Go to Foo</router-link>
-    <router-link to="/bar">Go to Bar</router-link>
-  </p>
-  <!-- 路由出口 -->
-  <!-- 路由匹配到的组件将渲染在这里 -->
-  <router-view></router-view>
-</div>
-
-<script>
-// 0. 如果使用模块化机制编程,導入Vue和VueRouter,要调用 Vue.use(VueRouter)
-
-// 1. 定义(路由)组件。
-// 可以从其他文件 import 进来
-const Foo = { template: '<div>foo</div>' }
-const Bar = { template: '<div>bar</div>' }
-
-// 2. 定义路由
-// 每个路由应该映射一个组件。 其中"component" 可以是
-// 通过 Vue.extend() 创建的组件构造器,
-// 或者,只是一个组件配置对象。
-// 我们晚点再讨论嵌套路由。
-const routes = [
-  { path: '/foo', component: Foo },
-  { path: '/bar', component: Bar }
-]
-
-// 3. 创建 router 实例,然后传 `routes` 配置
-// 你还可以传别的配置参数, 不过先这么简单着吧。
-const router = new VueRouter({
-  routes // (缩写)相当于 routes: routes
-})
-
-// 4. 创建和挂载根实例。
-// 记得要通过 router 配置参数注入路由,
-// 从而让整个应用都有路由功能
-const app = new Vue({
-  router
-}).$mount('#app')
-
-// 现在,应用已经启动了!
-</script>
-</body>
+
+	<head>
+		<meta charset="utf-8">
+		<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
+		<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
+		<script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.min.js"></script>
+	</head>
+
+	<body>
+		<div id="app">
+			<h1>Hello App!</h1>
+			<p>
+				<!-- 使用 router-link 组件来导航. -->
+				<!-- 通过传入 `to` 属性指定链接. -->
+				<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
+				<router-link to="/foo">Go to Foo</router-link>
+				<router-link to="/bar">Go to Bar</router-link>
+			</p>
+			<!-- 路由出口 -->
+			<!-- 路由匹配到的组件将渲染在这里 -->
+			<router-view></router-view>
+		</div>
+
+		<script>
+			// 0. 如果使用模块化机制编程,導入Vue和VueRouter,要调用 Vue.use(VueRouter)
+
+			// 1. 定义(路由)组件。
+			// 可以从其他文件 import 进来
+			const Foo = {
+				template: '<div>foo</div>'
+			}
+			const Bar = {
+				template: '<div>bar</div>'
+			}
+
+			// 2. 定义路由
+			// 每个路由应该映射一个组件。 其中"component" 可以是
+			// 通过 Vue.extend() 创建的组件构造器,
+			// 或者,只是一个组件配置对象。
+			// 我们晚点再讨论嵌套路由。
+			const routes = [{
+					path: '/foo',
+					component: Foo
+				},
+				{
+					path: '/bar',
+					component: Bar
+				}
+			]
+
+			// 3. 创建 router 实例,然后传 `routes` 配置
+			// 你还可以传别的配置参数, 不过先这么简单着吧。
+			const router = new VueRouter({
+				routes // (缩写)相当于 routes: routes
+			})
+
+			// 4. 创建和挂载根实例。
+			// 记得要通过 router 配置参数注入路由,
+			// 从而让整个应用都有路由功能
+			const app = new Vue({
+				router
+			}).$mount('#app')
+
+			// 现在,应用已经启动了!
+		</script>
+	</body>
+
 </html>

+ 52 - 0
Basic/路由/vue-router.html

@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<title>vue-router</title>
+<meta name="description" content="">
+<meta name="keywords" content="">
+<script type="text/javascript" src='js/vue.min.js'></script>
+<script type="text/javascript" src='js/vue-router.js'></script>
+</head>
+<body>
+    <div id='router'>
+    	<h1>Hello App !</h1>
+    	<p>
+    		<router-link to='/home'>Go to Home</router-link>
+    		<router-link to='/new'>Go to New</router-link>
+    	</p>
+    	<router-view></router-view>
+    </div>
+    <script type="text/javascript">
+    	//1.创建组件
+    	const Home={
+    		template:`<span>我是主页</span>`
+    	};
+    	const News={
+    		template:`<span>我是新闻</span>`
+    	};
+    	//2.配置路由
+    	const routes=[
+    			{
+    				path:'/home',component:Home
+    			},
+    			{
+    				path:'/new',component:News
+    			},
+    			//重定向.相当于404,
+    			{
+    				path:'*',redirect:'/home'
+    			}
+    	];
+    	//3.生成路由实例
+    	const router=new VueRouter({
+    		routes
+    	});
+  new Vue({
+  	el:'#router',
+  	router
+  })
+    </script>
+</body>
+</html>

+ 211 - 0
Basic/路由/vue-router.md

@@ -0,0 +1,211 @@
+<h1 style='color:rgb(230,3,135);'>2018 我所了解的 vue-router </h1>
+<img src='img/VueRouter.png'/>
+
+[查看原图](http://naotu.baidu.com/file/dbba90268bf1e5c34bfd39eaad721999?token=b39c89bd85d74046)
+
+<i> `vue-router` : 简称路由,简单说就是根据不同的 url 地址,显示不同的效果</i>
+
+`<router-link>`: 组件用于帮助用户进行<span style='color:rgb(230,3,135);'> 导航 </span>,也就是我们传统的 a 标签经常做的事;a 的标签用 href 属性来指定导航的目标地址,而  router-link 组件则用 to 属性来定目标地址;
+
+`<router-view>` : </span>是路由的出口,路由匹配到的组件将<span style='color:rgb(230,3,135);'> 渲染 </span>在这里,即渲染 `<router-link>`指向的目标地址。
+
+
+同一个路径可以匹配多个路由,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。
+
+## 创建简单的 vue-router
+
+<img src='img/router.jpg'/>
+
+ `<router-link>` 和 `<router-view>`  不必成双对的出现,可根据配置的不同路由渲染到一个 `<router-view>`
+
+```
+<div id='router'>
+  <router-link to='/home'>Go to Home</router-link>
+  <router-link to='/new'>Go to New</router-link>
+  <router-view></router-view>
+</div>
+//JavaScript 代码
+//1.创建组件
+ const Home={
+    template:`<span>我是主页</span>`
+  };
+  const News={
+    template:`<span>我是新闻</span>`
+  };
+//2.配置路由
+  const routersname=[
+	{
+    path:'/home',component:Home
+  },
+	{
+    	path:'/new',component:News
+  },
+	//重定向
+	{
+  	path:'*',redirect:'/home'
+	}];
+//3.生成路由实例
+ const router=new VueRouter({
+  routes:routersname
+  //此时 routers 和 routername 并不相等,所以不能在采用 es6 里面对象的简写方法
+  });
+  new Vue({
+  	el:'#router',
+  	router
+  })
+```
+注意:在创建路由实例的时候应该知道其中使用了 ES6 对象里面简洁的语法;即**在 ES6 中只写属性名不写属性值时,属性值就代表属性名所代表的变量**
+```
+const router = new VueRouter({
+  routes  // (缩写)相当于 routes: routes 是 ES6 对象里面简洁的语法
+})
+```
+当然我们也可以不采用简写,自己随便配置,还是刚刚那个例子
+
+```
+//2.配置路由
+const routersname=[
+  { path:'/home',component:Home },
+  { path:'/new',component:News },
+    //重定向
+  { path:'/new',component:News },
+];
+//3.生成路由实例
+const router=new VueRouter({
+  routes:routersname
+//此时 routers 和 routername 并不相等
+//所以不能在采用 es6 里面对象的简写方法
+});
+```
+所以 router 后面的属性值应该始终和配置路由时候的变量一样
+
+[查看源码](https://github.com/sunseekers/Vue/blob/master/vue-router.html)
+
+## 嵌套的 vue-router 
+实际生活中的我们经常会遇到 多层嵌套的组件组合而成,URL 中各段动态路径也按某种结构对应嵌套的各层组件
+
+这时候我们怎么办呐?
+
+其实嵌套路由很简单,只需要加上一个 children 就好,children 里面的写法和外面的一样
+
+<img src='img/router1.png'/>
+
+$route.params: 表示当前的参数即冒号后面的东西
+
+/detail/:id/age/:age  --->$route.params 表示  id 和 age 组成的对象
+
+[查看源码](https://github.com/sunseekers/Vue/blob/master/vue-router2.html)
+
+## 路由的两种实例方法 
+
+> router.push({path:'/home'}): 直接添加一个路由,表现为切换路由,往历史记录里面添加一个历史记录
+
+> router.replace({path:'news'}): 替换路由,历史记录里面没有添加记录
+
+<img src='img/router.gif'/>
+
+引入了过渡动画 ,顺便可以温习一下 transform 组件的知识,页面效果看起来好看多了,哈哈哈哈
+
+[查看源码](https://github.com/sunseekers/Vue/blob/master/routerTransform.html)
+
+## 配置路由的模式
+设置路由的跳转方式
+
+mode 表示路由的配置模式:两种
+
+> 1. hash模式(默认):使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,**页面不会重新加载**。
+
+> 2. history模式: 通过history完成 URL **跳转而无须重新加载页面**。
+
+```
+//创建路由实例
+const router = new VueRouter({
+  mode: 'history',//跳转而无须重新加载页面
+  routes
+})
+```
+<img src='img/mode.gif'/>
+
+## 路由的滚动 scrollBehavior
+不知道你们有没有遇到过这样的情况?
+
+1. 当切换到新路由时,我想要想要页面滚到顶部!!!
+
+2. 当切换到新路由时,保持原先的滚动位置!!!!
+
+3. 当切换到新路由时,我想随意定位!!!!
+
+这时候该怎么办???
+
+告诉你 **vue-router** 能做到,而且很很好,它让你可以自定义路由切换时页面如何滚动。
+```
+const router = new VueRouter({
+  routes,
+  scrollBehavior (to, from, savedPosition) {
+    // return 期望滚动到哪个的位置
+     return {x:0,y:0} //对于所有路由导航,简单地让页面滚动到顶部
+  }
+})
+```
+## 路由监听 watch
+在 vue 中 watch 用来监听当一个数据属性值发送变化时,就可以调用的函数;属于异步操作;一般情况下,我们建议用 computed 或者 menthods 代替。对于大型的应用我们就建议使用 watch;
+
+关于 mothds, computed, watch 三者的具体区别,推荐看大漠老师写的[在Vue中何时使用方法、计算属性或观察者](https://www.w3cplus.com/vue/when-to-use-methods-computed-properties-or-watchers.html)
+
+回到 vue-router ,当我们切换路由的时候,希望某些属性也跟着路由变化;例如
+<img src='img/vue111.png'/>
+这时候我们就可以用 watch 来监听路由,当路由发生变化时,相对于的样式也跟着显示或隐藏;这只是一个很简单的例子
+
+
+## `<router-link>` 属性
+
+> 1. to :相当于 a 的标签用 href 属性,来指定导航的目标地址;
+
+导航的目标地址的几种写法
+```
+  1.字符串表示
+  <router-link to='Home'>Home</router-link>
+
+  2.v-bind 绑定属性
+  <router-link :to='Home'>Home</router-link>
+
+  3.对象表示
+  <router-link :to="{path:'Home'}">Home</router-link>
+
+  4.命名的路由
+  <router-link :to="{name:'Home',params:{home:123}}">Home</router-link>
+
+  5.带查询参数,下面的结果为 /Home?plan=private
+  <router-link :to="{path: 'Home', query: { plan: 'private' }}">Home</router-link>
+```
+我们常用前两种方法
+
+>  2. replace
+
+   `<router-link to='Home' replace>Home</router-link>`
+   给它设置了 replace 属性, 会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。详情请看上面 router.replace 和 router.push() 的区别
+
+>  3. 设置 tag 就会把 `<router-link>` 渲染成某种标签
+ ```
+<router-link to="/foo" tag="li">foo</router-link>
+   <!-- 渲染结果 -->
+<li class='router-link-exact-active router-link-active'> foo </li>
+
+```
+## `<router-view>` 属性
+
+> name 给 `<router-view>` 设置一个名字,当有过个视图的时候,能够在保证每个视图中精确准确的定位
+
+```
+<router-link to="/">/</router-link>
+<router-link to="/other">other</router-link>
+
+<router-view></router-view>
+<router-view name="a"></router-view>
+<router-view name="b"></router-view>
+```
+[举个例子](https://github.com/sunseekers/Vue/blob/master/vue-routername.html)
+
+我还是个 Vue 的初学者,如果文章中有不对之处,还请指正,如果你有更好的经验或建议,欢迎在下面的评论中与我们一起分享
+
+

+ 51 - 0
Basic/路由/vue-router2.html

@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<title>嵌套路由</title>
+<meta name="description" content="">
+<meta name="keywords" content="">
+<script type="text/javascript" src='js/vue.min.js'></script>
+<script type="text/javascript" src='js/vue-router.js'></script>
+</head>
+<body>
+    <div id='router'>
+    	<router-link to='/home'>Go to Home</router-link>
+    		<router-link to='/user'>Go to User</router-link>
+    	<router-view></router-view>
+    </div>
+    <script type="text/javascript">
+    	const Home={
+    		template:`<span>我是主页</span>`
+    	};
+    	const username={
+    		//$route.params: 表示冒号后面的一个对象
+    		template:`<span>我是{{$route.params}}</span>`
+    	};
+    	const News={
+    		template:`<div>
+    		<h3>我是用户</h3>
+				<ul><li><router-link to='/user/sunseekers'>用户信息</router-link></li><ul>
+				<router-view></router-view>
+    		</div>`
+    	};
+    	const routes=[
+    	{path:'/home',component:Home},
+    	{
+    		path:'/user',component:News,
+    		//配置子路由或者说是嵌套路由,只需要在嵌套或者父路由里面加一个 
+    		//children[{path:'',component:}]就好,很形象,很好记
+    		children:[
+    		{path:':username',component:username}
+    		]},
+    	{path:'*',redirect:'/home'}
+    	];
+    	const router=new VueRouter({routes});
+    	new Vue({
+    		el:'#router',
+    		router
+    	})
+    </script>
+</body>
+</html>

+ 61 - 0
Basic/路由/vue-routername.html

@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<title>给路由定义名字</title>
+<meta name="description" content="">
+<meta name="keywords" content="">
+<link href="" rel="stylesheet">
+</head>
+<body>
+  <div id="app">
+    <h1>Named Views</h1>
+    <ul>
+      <li>
+        <router-link to="/">/</router-link>
+      </li>
+      <li>
+        <router-link to="/other">/other</router-link>
+      </li>
+    </ul>
+    <router-view></router-view>
+    <router-view name="a"></router-view>
+    <router-view name="b"></router-view>
+  </div>
+  <script type="text/javascript" src='js/vue.min.js'></script>
+  <script type="text/javascript" src='js/vue-router.js'></script>
+  <script type="text/javascript">
+    const Foo = { template: '<div>11111</div>' }
+    const Bar = { template: '<div>22222</div>' }
+    const Baz = { template: '<div>33333</div>' }
+
+    const router = new VueRouter({
+      routes: [
+        { path: '/',
+          components: {
+            default: Foo,
+            a: Bar,
+            b: Baz
+          }
+        },
+        {
+          path: '/other',
+          components: {
+            default: Baz,
+            a: Bar,
+            b: Foo
+          }
+        },
+        {
+          path:'*',redirect:'/'
+        }
+      ]
+    })
+    new Vue({
+      router,
+      el: '#app'
+    })
+  </script>
+</body>
+</html>

+ 1 - 0
README.md

@@ -16,6 +16,7 @@
 过渡 & 动画
 
 条件与循环
+
 04. 处理用户输入
 05. 按钮事件
 06. 组件

Some files were not shown because too many files changed in this diff