🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
**vue-router** [[vue官方网站 vue-router]](https://router.vuejs.org/) Vue Router is the official router for [Vue.js](http://vuejs.org/). It deeply integrates with Vue.js core to make building `Single Page Applications` with Vue.js a breeze. Features include: * Nested route/view mapping * Modular, component-based router configuration * Route params, query, wildcards * View transition effects powered by Vue.js' transition system * Fine-grained navigation control * Links with automatic active CSS classes * HTML5 history mode or hash mode, with auto-fallback in IE9 * Customizable Scroll Behavior Creating a Single-page Application with Vue + Vue Router is dead simple. With Vue.js, we are already composing our application with components. When adding Vue Router to the mix, all we need to do is map our components to the routes and let Vue Router know where to render them. ---- **目录内容** [TOC] ---- ## Installation ### Direct Download / CDN [Unpkg.com](https://unpkg.com/) provides npm-based CDN links. The above link will always point to the latest release on npm. You can also use a specific version/tag via URLs like `https://unpkg.com/vue-router@2.0.0/dist/vue-router.js`. Include `vue-router` after Vue and it will install itself automatically: ~~~html <script src="/path/to/vue.js"></script> <script src="/path/to/vue-router.js"></script> ~~~ ### npm ~~~shell $ npm install vue-router ~~~ When used with a module system, you must explicitly install the router via`Vue.use()`: ~~~javascript import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) ~~~ You don't need to do this when using global script tags. ### Dev Build You will have to clone directly from GitHub and build`vue-router`yourself if you want to use the latest dev build. ~~~shell $ git clone https://github.com/vuejs/vue-router.git node_modules/vue-router $ cd node_modules/vue-router $ npm install $ npm run build ~~~ ## A basic example * HTML ~~~html <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <h1>Hello App!</h1> <p> <!-- use router-link component for navigation. --> <!-- specify the link by passing the `to` prop. --> <!-- `<router-link>` will be rendered as an `<a>` tag by default --> <router-link to="/foo">Go to Foo</router-link> <router-link to="/bar">Go to Bar</router-link> </p> <!-- route outlet --> <!-- component matched by the route will render here --> <router-view></router-view> </div> ~~~ * JavaScript ~~~javascript // 0. If using a module system (e.g. via vue-cli), import Vue and VueRouter // and then call `Vue.use(VueRouter)`. // 1. Define route components. // These can be imported from other files const Foo = { template: '<div>foo</div>' } const Bar = { template: '<div>bar</div>' } // 2. Define some routes // Each route should map to a component. The "component" can // either be an actual component constructor created via // `Vue.extend()`, or just a component options object. // We'll talk about nested routes later. const routes = [ { path: '/foo', component: Foo }, { path: '/bar', component: Bar } ] // 3. Create the router instance and pass the `routes` option // You can pass in additional options here, but let's // keep it simple for now. const router = new VueRouter({ routes // short for `routes: routes` }) // 4. Create and mount the root instance. // Make sure to inject the router with the router option to make the // whole app router-aware. const app = new Vue({ router }).$mount('#app') // Now the app has started! ~~~ By injecting the router, we get access to it as`this.$router`as well as the current route as`this.$route`inside of any component: ~~~javascript // Home.vue export default { computed: { username() { // We will see what `params` is shortly return this.$route.params.username } }, methods: { goBack() { window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } } ~~~ Throughout the docs, we will often use the`router`instance. Keep in mind that `this.$router` is exactly the same as using `router`. The reason we use `this.$router` is because we don't want to import the router in every single component that needs to manipulate routing. Notice that a `<router-link>` automatically gets the `.router-link-active` class when its target route is matched. You can learn more about it in its [API reference](https://router.vuejs.org/api/#router-link). You can also check out this example[live](https://jsfiddle.net/yyx990803/xgrjzsup/). ## Vue 页面跳转方式 与 参数传递 编程导航 [[参考文档]](https://blog.csdn.net/muguli2008/article/details/102789504) ### 标签跳转:`<router-link>`映射路由 1、不带参数跳转 ~~~html <!-- home页面(首页) --> <template> <!-- 在Vue中的<router-link>标签中,到页面最终还是转为<a>标签 --> <router-link to="/about"> <button>打开关于我们 - 不带参数1</button> </router-link> <router-link :to="{path: '/about'}"> <button>打开关于我们 - 不带参数2</button> </router-link> </template> ~~~ 2、带参数跳转 ~~~html <!-- home页面(首页) --> <template> <router-link :to="{path: '/about', query: {id: 1024, name:'mupiao', age: 28 }}"> <button>打开关于我们 - 带参数1</button> </router-link> <router-link :to="{name: 'About', params: {id: 1024, name:'mupiao', age: 28 }}"> <button>打开关于我们 - 带参数2</button> </router-link> </template> ~~~ 3、接收参数 ~~~ // About页面(关于我们) <template> <section>关于我们</section> </template> <script> export default { name: "About", data() { return {}; }, created() { // 在Vue实例被创建之后的钩子函数中,接收home页面传过来的参数 // 以query方式接收参数:【query传递数据是通过URL传递的,类似ajax中的get方式】 console.log(this.$route.query.id); // 1014 console.log(this.$route.query.name); // mupiao console.log(this.$route.query.age); // 28 // 以params方式接收参数:【params方式,类似ajax中的post方式】 console.log(this.$route.params.id); // 1014 console.log(this.$route.params.name); // mupiao console.log(this.$route.params.age); // 28 } } </script> ~~~ **显示子路由视图一定要加上`<router-view></router-view>`** ~~~ // Main主框架页面 <template> <Layout> <Header></Header> <Content> <!-- 显示子路由视图 --> <router-view></router-view> </Content> <Footer></Footer> </Layout> </template> <script> import Header from "@/components/Header.vue"; import Footer from "@/components/Footer.vue"; export default { name: "Main", components: { Header, Footer }, data() { return {}; }, mounted() {}, methods: {} }; </script> <style lang="scss" scoped> .ivu-layout { .ivu-layout-content { min-height: 88vh; } } </style> ~~~ ### 编程式路由跳转: `this.$router` `this.$router.push()`:跳转到指定url路径,并向`history`栈中添加一个记录,点击后退会返回到上一个页面。 `this.$router.replace()` :跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)。 `this.$router.go(n) ()`:向前或者向后跳转n个页面,n可为正整数或负整数。 1、不带参数跳转 ~~~ <!-- Home页面(首页) --> <template> <router-link :to="{path: '/about'}"> <button>打开关于我们</button> </router-link> <button @click="open">打开关于我们</button> </template> <script> export default { name: "Home", data() { return {}; }, methods: { open() { this.$router.push('/about'); } }, } </script> ~~~ 2、带参数跳转 ~~~ <!-- Home页面(首页) --> <template> <router-link :to="{path: '/about'}"> <button>打开关于我们</button> </router-link> <button @click="open1">打开关于我们 - query方式</button> <button @click="open2">打开关于我们 - params方式</button> </template> <script> export default { name: "Home", data() { return {}; }, methods: { // query方式,与path搭配使用,而params 会被忽略, // 带查询参数,变成 /about?id=2048&book=了不起的Node.js&job=Web前端 open1() { this.$router.push({ path: '/about', query: { id: 2048, book: "了不起的Node.js", job: "Web前端" } }); }, //⚠️注:如果要传递的参数很长时,请用params方式, //因为query方式是通过URL传递的,而URL传参数长度是有限制的哦!! // params方式,与name搭配使用 open2() { this.$router.push({ name: "About", // ⚠️注:这里不能用path路径,只能用name【请对照router.js中的路由规则中的name项,还有就是一般首字母大写】,否则取不到传过去的数据 params: { id: 2048, book: "了不起的Node.js", job: "Web前端" } }); } }, } </script> ~~~ 3、接收参数 ~~~ // About页面(关于我们) <template> <section>关于我们</section> </template> <script> export default { name: "About", data() { return {}; }, created() { // 在Vue实例被创建之后的钩子函数中,接收home页面传过来的参数 //⚠️注:在传递参数时,用什么方式传参,就用什么方式接收!! // 以query方式接收参数:【query传递数据是通过URL传递的,类似ajax中的get方式】 console.log(this.$route.query.id); // 2048 console.log(this.$route.query.book); // 了不起的Node.js console.log(this.$route.query.job); // Web前端 // 以params方式接收参数:【params方式,类似ajax中的post方式】 console.log(this.$route.params.id); // 2048 console.log(this.$route.params.book); // 了不起的Node.js console.log(this.$route.params.job); // Web前端 // this.$route 路由信息对象 console.log(this.$route); //this.$route 对象中包涵了路由的相关信息,请自看!! </script>   ~~~ 简单总结 ~~~javascript //1. 不带参数 this.$router.push('/home') this.$router.push({name:'home'}) this.$router.push({path:'/home'}) //2. query传参 this.$router.push({name:'home',query: {id:'1'}}) this.$router.push({path:'/home',query: {id:'1'}}) // html 取参 $route.query.id // script 取参 this.$route.query.id //3. params传参 this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name // 路由配置 path: "/home/:id" 或者 path: "/home:id" , // 不配置path ,第一次可请求,刷新页面id会消失 // 配置path,刷新页面id会保留 // html 取参 $route.params.id // script 取参 this.$route.params.id ~~~ ### 获取路由上的参数:`this.$route` >[warning]获取路由上面的参数,用的是`$route`,后面没有r `query`和`params`区别 `query`类似`get`, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params。刷新页面id还在 。 `params`类似`post`, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失 params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。 params一旦设置在路由,params就是路由的一部分,如果这个路由有params传参,但是在跳转的时候没有传这个参数,会导致跳转失败或者页面会没有内容。 params、query不设置也可以传参,但是params不设置的时候,刷新页面或者返回参数会丢失, 两者都可以传递参数,区别是什么? query 传参配置的是path,而params传参配置的是name,在params中配置path无效 query在路由配置不需要设置参数,而params必须设置 query传递的参数会显示在地址栏中 params传参刷新会无效,但是query会保存传递过来的值,刷新不变 ### 浏览器跳转 ~~~javascript //HTML标签打开外部链接 <a target="_blank" href="https://www.baidu.com/s?wd=Vue">百度一下 Vue</a> //在当前页面打开URL页面 window.location.href = "https://www.baidu.com/s?wd=Vue"; //打开一个新的浏览器窗口 window.open("https://www.baidu.com/s?wd=Vue", "_blank", "width=1000, height=500", true); ~~~ ## Vue常用路由规则配置 ~~~javascript import Vue from 'vue' import VueRouter from 'vue-router' import Main from '../views/Main.vue' // 抽离出在这个路由配置表中共用的页面视图,以方便多处使用 const Login = () => import(/* webpackChunkName: "Login" */ '../views/Login.vue'); const News = () => import(/* webpackChunkName: "News" */ '../views/News.vue'); const NotFound = () => import(/* webpackChunkName: "NotFound" */ '../views/NotFound.vue'); Vue.use(VueRouter); const routes = [ { path: '/', // 网站首页 name: 'Home', component: () => import('../views/Home.vue') }, { path: '/login', name: 'Login', component: Login }, { path: '/regist', name: 'Regist', component: () => import('../views/Regist.vue') }, { path: '/main', name: 'Main', meta: { userauth: true // 开启用户鉴权(用户需登录后,才能访问) }, component: Main, children: [ // 子路由 { path: '/news/:id(\\d+)', name: 'News', meta: { userauth: true }, component: News, children: [ // 第三级子路由 { path: '/main/news/alert', name: 'Alert', component: () => import('../views/Alert.vue') }, { path: '/card/:listId(\\d+)/list/:listId(\\d+)', name: 'Card', component: () => import('../views/Card.vue') } ] }, { path: '/info/:id(\\d+)', name: 'Info', meta: { userauth: true }, component: () => import(/* webpackChunkName: "Info" */ '../views/Info.vue') }, { path: '/send', name: 'Send', meta: { userauth: true }, component: () => import('../views/Send.vue') }, // 默认显示的子路由 { path: '', name: 'News', component: News } ], }, { path: '/about', name: 'About', meta: { userauth: true }, // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') }, { path: '/notfound', name: 'NotFound', component: NotFound }, // 如果找不到对应的路由(页面)就显示404页面 { path: '*', name: 'NotFound', component: NotFound } ]; const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }); router.beforeEach((to, from, next) => { // 在进入路由前,判断到该路由需要鉴权(用户登录)则验证用户信息(!Store.state.user.userinfo 没有用户信息),不通过则跳转到登录页。 if (to.matched.some(matched => matched.meta.userauth) && !Store.state.user.userinfo) { next({ name: 'Login' }); } else { next(); } }); export default router; ~~~ ## Navigation Guards [[官方文档]](https://router.vuejs.org/guide/advanced/navigation-guards.html) ### Global Before Guards ### Global Resolve Guards ### Global After Hooks ### Per-Route Guard ### In-Component Guards you can directly define route navigation guards inside route components (the ones passed to the router configuration) with the following options: * `beforeRouteEnter` * `beforeRouteUpdate` * `beforeRouteLeave` ~~~javascript const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // called before the route that renders this component is confirmed. // does NOT have access to `this` component instance, // because it has not been created yet when this guard is called! }, beforeRouteUpdate (to, from, next) { // called when the route that renders this component has changed, // but this component is reused in the new route. // For example, for a route with dynamic params `/foo/:id`, when we // navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance // will be reused, and this hook will be called when that happens. // has access to `this` component instance. }, beforeRouteLeave (to, from, next) { // called when the route that renders this component is about to // be navigated away from. // has access to `this` component instance. } } ~~~ ### The Full Navigation Resolution Flow 1. Navigation triggered. 2. Call`beforeRouteLeave`guards in deactivated components. 3. Call global`beforeEach`guards. 4. Call`beforeRouteUpdate`guards in reused components. 5. Call`beforeEnter`in route configs. 6. Resolve async route components. 7. Call`beforeRouteEnter`in activated components. 8. Call global`beforeResolve`guards. 9. Navigation confirmed. 10. Call global`afterEach`hooks. 11. DOM updates triggered. 12. Call callbacks passed to`next`in`beforeRouteEnter`guards with instantiated instances. ### 示例 [[出处]](https://www.cnblogs.com/coolzone/p/9420840.html) 功能要求: 1. 列举需要判断登录状态的“路由集合”,当跳转至集合中的路由时,如果“未登录状态”,则跳转到登录页面LoginPage; 2. 当直接进入登录页面LoginPage时,如果“已登录状态”,则跳转到首页HomePage; ~~~js import Vue from 'vue'; import Router from 'vue-router'; import LoginPage from '@/pages/login'; import HomePage from '@/pages/home'; import GoodsListPage from '@/pages/good-list'; import GoodsDetailPage from '@/pages/good-detail'; import CartPage from '@/pages/cart'; import ProfilePage from '@/pages/profile'; Vue.use(Router) const router = new Router({ routes: [ { path: '/', // 默认进入路由 redirect: '/home' //重定向 }, { path: '/login', name: 'login', component: LoginPage }, { path: '/home', name: 'home', component: HomePage }, { path: '/good-list', name: 'good-list', component: GoodsListPage }, { path: '/good-detail', name: 'good-detail', component: GoodsDetailPage }, { path: '/cart', name: 'cart', component: CartPage }, { path: '/profile', name: 'profile', component: ProfilePage }, { path: '\*\*', // 错误路由 redirect: '/home' //重定向 }, ] }); // 全局路由守卫 // to: Route: 即将要进入的目标 路由对象 // from: Route: 当前导航正要离开的路由 // next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。 router.beforeEach((to, from, next) => { console.log('navigation-guards'); const nextRoute = ['home', 'good-list', 'good-detail', 'cart', 'profile']; let isLogin = global.isLogin; // 是否登录 // 未登录状态;当路由到nextRoute指定页时,跳转至login if (nextRoute.indexOf(to.name) >= 0) { if (!isLogin) { console.log('what fuck'); router.push({ name: 'login' }) } } // 已登录状态;当路由到login时,跳转至home if (to.name === 'login') { if (isLogin) { router.push({ name: 'home' }); } } next(); }); export default router; ~~~ ## API [[官方文档-API]](https://router.vuejs.org/api/#router-link)