路由 — Vue.js

1.官方路由

对于大多数单页面应用,都推荐使用官方支持的 vue-router 库。

1.1 入门

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
			.router-link-active {
			  color: red;
			}
        </style>
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
		<div id="app">
			<h1>Hello App!</h1>
			<p>
				<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>
			const Foo = { template: '<div>foo</div>' }
			const Bar = { template: '<div>bar</div>' }

			const routes = [
			  { path: '/foo', component: Foo },
			  { path: '/bar', component: Bar }
			]

			const router = new VueRouter({
			  routes
			})

			const app = new Vue({
			  router
			}).$mount('#app')
        </script>
    </body>
</html>

注意:如果组件包含install方法,使用该组件时需要通过Vue.use(...)显式声明。这里没有使用Vue.use(...),显然是跟引入的库的版本有关。

1.2 动态路由匹配

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
			.router-link-active {
			  color: red;
			}
        </style>
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
		<div id="app">
			<h1>Hello App!</h1>
			<p>
				<router-link to="/user/1">用户1</router-link>
				<router-link to="/user/2">用户2</router-link>
			</p>
			<router-view></router-view>
		</div>
        <script>			
			const User = {
			  template: '<div>User {{ $route.params.id }}</div>'
			}		

			const router = new VueRouter({
			  routes: [
				{path: '/user/:id', component: User}
			  ]
			})

			const app = new Vue({
			  el: '#app',
			  router
			})
        </script>
    </body>
</html>

注意到/user/:id:id是动态的部分,我们通过$route.params可以访问到这些动态的内容。

下面监听组件参数的变化。

const User = {
  template: '<div>User {{ $route.params.id }}</div>',
  watch: {
	$route: function(to, from){
		console.log(to, from);
	}
  }			  
}
/*
const User = {
  template: '<div>User {{ $route.params.id }}</div>',			  
  beforeRouteUpdate (to, from, next) {
	console.log(to, from);
  }
}
*/

1.3 嵌套路由

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
			.router-link-active {
			  color: red;
			}
        </style>
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
		<div id="app">
			<h1>Hello App!</h1>
			<p>
				<router-link to="/user/foo">/user/foo</router-link>
				<router-link to="/user/foo/profile">/user/foo/profile</router-link>
				<router-link to="/user/foo/posts">/user/foo/posts</router-link>
			</p>
			<router-view></router-view>
		</div>
        <script>			
			const User = {
			  template: `
				<div class="user">
				  <h2>User {{ $route.params.id }}</h2>
				  <router-view></router-view>
				</div>
			  `
			}
			
			const UserHome = { template: '<div>Home</div>' }
			const UserProfile = { template: '<div>Profile</div>' }
			const UserPosts = { template: '<div>Posts</div>' }

			const router = new VueRouter({
			  routes: [
				{path: '/user/:id', component: User,
				 children: [
					{ path: '', component: UserHome },
					{
						path: 'profile',
						component: UserProfile
					},
					{
						path: 'posts',
						component: UserPosts
					}
				 ]}
			  ]
			})

			const app = new Vue({
			  el: '#app',
			  router
			})
        </script>
    </body>
</html>

1.4 编程式导航

1.4.1 router.push(location, onComplete, onAbort)

<router-link :to="...">等价于router.push(...)

router.push('home')
// /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })

const userId = '123'
router.push({ name: 'user', params: { userId } }) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// This will NOT work
router.push({ path: '/user', params: { userId } }) // -> /user

1.4.2 router.replace(location, onComplete, onAbort)

<router-link :to="..." replace>等价于router.replace(...)

看一个例子。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
			.router-link-active {
			  color: red;
			}
        </style>
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
		<div id="app">
			<h1>Hello App!</h1>
			<p>
				<button @click="pushShow('/user/foo')">/user/foo</button>
				<button @click="pushShow('/user/foo/profile')">/user/foo/profile</button>
				<button @click="pushShow('/user/foo/posts')">/user/foo/posts</button>
				<!-- 
				<button @click="replaceShow('/user/foo')">/user/foo</button>
				<button @click="replaceShow('/user/foo/profile')">/user/foo/profile</button>
				<button @click="replaceShow('/user/foo/posts')">/user/foo/posts</button>
				-->
				
				<!-- <button @click="$router.back()">回退</button> -->
				<button @click="goBack()">回退</button>
				<!--
				<router-link to="/user/foo">/user/foo</router-link>
				<router-link to="/user/foo/profile">/user/foo/profile</router-link>
				<router-link to="/user/foo/posts">/user/foo/posts</router-link>
				-->
			</p>
			<router-view></router-view>
		</div>
        <script>
			const User = {
			  template: `
				<div class="user">
				  <h2>User {{ $route.params.id }}</h2>
				  <router-view></router-view>
				</div>
			  `
			}
			
			const UserHome = { template: '<div>Home</div>' }
			const UserProfile = { template: '<div>Profile</div>' }
			const UserPosts = { template: '<div>Posts</div>' }

			const router = new VueRouter({
			  routes: [
				{path: '/user/:id', component: User,
				 children: [
					{ path: '', component: UserHome },
					{
						path: 'profile',
						component: UserProfile
					},
					{
						path: 'posts',
						component: UserPosts
					}
				 ]}
			  ]
			})

			const app = new Vue({
			  el: '#app',
			  router,
			  methods: {
				pushShow (id) {
					if(id){
						this.$router.push(id);
					}
				},
				replaceShow (id) {
					if(id){
						this.$router.replace(id);
					}
				},
				goBack () {
					window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')
				}
			  }
			})
        </script>
    </body>
</html>

1.5 命名路由

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
			.router-link-active {
			  color: red;
			}
        </style>
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
		<div id="app">
			<h1>Hello App!</h1>
			<p>
				<!--
				<button @click="pushShow({path: '/user/foo'})">/user/foo</button>
				<button @click="pushShow({path: '/user/foo/profile'})">/user/foo/profile</button>
				<button @click="pushShow({path: '/user/foo/posts'})">/user/foo/posts</button>
				-->
				<!-- 
				<button @click="pushShow({name: 'user', params: {id: 'foo'}})">/user/foo</button>
				<button @click="pushShow({name: 'uProfile', params: {id: 'foo'}})">/user/foo/profile</button>
				<button @click="pushShow({name: 'uPosts', params: {id: 'foo'}})">/user/foo/posts</button>
				-->
				<router-link :to="{name: 'user', params: {id: 'foo'}}">/user/foo</router-link>
				<router-link :to="{name: 'uProfile', params: {id: 'foo'}}">/user/foo/profile</router-link>
				<router-link :to="{name: 'uPosts', params: {id: 'foo'}}">/user/foo/posts</router-link>
			</p>
			<router-view></router-view>
		</div>
        <script>
			const User = {
			  template: `
				<div class="user">
				  <h2>User {{ $route.params.id }}</h2>
				  <router-view></router-view>
				</div>
			  `
			}
			
			const UserHome = { template: '<div>Home</div>' }
			const UserProfile = { template: '<div>Profile</div>' }
			const UserPosts = { template: '<div>Posts</div>' }

			const router = new VueRouter({
			  routes: [
				{path: '/user/:id', name: 'user', component: User,
				 children: [
					{ path: '', component: UserHome },
					{
						path: 'profile',
						name: 'uProfile',
						component: UserProfile
					},
					{
						path: 'posts',
						name: 'uPosts',
						component: UserPosts
					}
				 ]}
			  ]
			})

			const app = new Vue({
			  el: '#app',
			  router,
			  methods: {
				pushShow (id) {
					if(id){
						this.$router.push(id);
					}
				}
			  }
			})
        </script>
    </body>
</html>

注意:如果父路由带动态参数,子路由就需要传params,比如<router-link :to="{name: 'uProfile', params: {id: 'foo'}}">

1.6 命名视图

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
			.router-link-active {
			  color: red;
			}
        </style>
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
		<div id="app">
			<h1>Hello App!</h1>
			<p>
				<router-link to="/foo">Foo</router-link>
				<router-link to="/other">Other</router-link>
			</p>
			<router-view></router-view>
			<router-view name="a"></router-view>
			<router-view name="b"></router-view>
		</div>
        <script>			
			const Foo = { template: '<div>Foo</div>' }
			const Bar = { template: '<div>Bar</div>' }
			const Baz = { template: '<div>Baz</div>' }

			const router = new VueRouter({
			  routes: [
				{
					path: '/foo',
					components: {
						default: Foo,
						a: Bar,
						b: Baz
					}
				},
				{
					path: '/other',
					components: {
						default: Baz,
						a: Bar,
						b: Foo
					}
				}
			  ]
			})

			const app = new Vue({
			  el: '#app',
			  router
			})
        </script>
    </body>
</html>

1.6.1 嵌套命名视图

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
			.router-link-active {
			  color: red;
			}
        </style>
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
		<div id="app">
			<h1>Hello App!</h1>
			<router-view></router-view>
		</div>
        <script>
			const FooSettings = {
				template: `<div><router-link to="/foo/bar">Bar</router-link>  <router-link to="/foo/baz">Baz</router-link></div>`
			}
			const Foo = {
				template: `<div>Foo
				<div><FooSettings/></div>
				<router-view></router-view><router-view name="helper"></router-view></div>`,
				components: { FooSettings }
			}
			const Bar = { template: '<div>Bar</div>' }
			const Baz = { template: '<div>Baz</div>' }
			const Baz1 = { template: '<div>Baz1</div>' }

			const router = new VueRouter({
			  routes: [
				{
					path: '/foo',
					component: Foo,
					children: [{
						path: 'bar',
						component: Bar
					}, {
						path: 'baz',
						components: {
							default: Baz,
							helper: Baz1
						}
					}]
				}
			  ]
			})
			
			router.push('/foo/bar')

			const app = new Vue({
			  el: '#app',
			  router
			})
        </script>
    </body>
</html>

1.7 重定向和别名

1.1 入门的例子中,我们可以把路由改为:

const routes = [
  { path: '', redirect: '/bar' },			  
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

这样页面就会重定向到路由/bar
我们也可以在重定向中使用命名路由。

const routes = [
  { path: '', redirect: {name: 'foo'} },			  
  { path: '/foo', component: Foo, name: 'foo' },
  { path: '/bar', component: Bar, name: 'bar' }
]

通过alias我们可以给路由起别名。重定向路由访问地址会发生改变,而路由别名意味着访问地址不会发生改变,但是使用pathalias声明的路由访问的是同一个东西。

const routes = [			  
  { path: '/foo', component: Foo, alias: '/abc' },
  { path: '/bar', component: Bar, alias: '/def' }
]

提示:这里alias我没有试成功,不知道是不是 vue-router 版本的问题。

1.8 传递props到路由组件

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
            .router-link-active {
              color: red;
            }
        </style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
        <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
        <div id="app">
            <h1>Hello App!</h1>
            <p>
                <router-link to="/foo/123">Go to Foo</router-link>
            </p>
            <router-view></router-view>
        </div>
        <script>
            const Foo = { template: '<div>foo {{ $route.params.id }}</div>' }

            const routes = [
              { path: '/foo/:id', component: Foo }
            ]

            const router = new VueRouter({
              routes
            })

            const app = new Vue({
              router
            }).$mount('#app')
        </script>
    </body>
</html>

为了解耦组件和路由器,我们可以把JS改写成:

const Foo = { props: ['id'], template: '<div>foo {{ id }}</div>' }

const routes = [
  { path: '/foo/:id', component: Foo, props: true }
]

const router = new VueRouter({
  routes
})

const app = new Vue({
  router
}).$mount('#app')
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">      
        <style>
            .router-link-active {
              color: red;
            }
        </style>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
        <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
    </head>
    <body>
        <div id="app">
            <h1>Hello App!</h1>
            <p>
                <router-link to="/foo">Go to Foo</router-link>
				<router-link to="/dynamic/2">DynamicPropsFunction</router-link>
            </p>
            <router-view></router-view>
        </div>
        <script>
			function dynamicPropsFn (route) {
			  const now = new Date()
			  return {
				name: (now.getFullYear() + parseInt(route.params.years)) + '!'
			  }
			}
			
			const Foo = { props: { name: {type: String, default: 'Vue!'} }, template: '<div>foo {{ name }}</div>' }

			const routes = [
			  { path: '/foo', component: Foo, props: {name: 'bar'} },
			  { path: '/dynamic/:years', component: Foo, props: dynamicPropsFn }
			]

			const router = new VueRouter({
			  routes
			})

			const app = new Vue({
			  router
			}).$mount('#app')
        </script>
    </body>
</html>

路由中的props可以设置为布尔值、对象甚至是函数。

参考:

posted @ 2021-01-22 17:27  gzhjj  阅读(119)  评论(0编辑  收藏  举报