【Vue路由系统详述】

旧时模样 提交于 2019-11-28 15:49:29

原文: http://blog.gqylpy.com/gqy/280

一切分离都是为了更好的结合,本文详细介绍了前后端架构分离之后,前端如何实现路由的控制,即Vue路由系统——VueRouter.

VueRouter下载地址(默认最新版本):https://unpkg.com/vue-router@3.0.1/dist/vue-router.js

@
*
VueRouter实现原理:**

==根据锚点值的改变,修改组件内容.==

我们先来看看不使用VueRouter,自己实现路由的控制,如下代码:

<body> <div id="app"></div> <script>     let oDiv = document.getElementById('app');     window.onhashchange = function () {         // vue-router的实现原理是根据锚值的改变来对页面进行切换         switch (location.hash) {             case '#/login':                 oDiv.innerHTML=`<h1>我是登陆页面</h1>`;                 break;             case '#/register':                 oDiv.innerHTML = `<h1>我是注册页面</h1>`;                 break;             // 输入其他路径将显示为首页             default:                 oDiv.innerHTML = `<h1>我是首页</h1>`;                 break;         }     };     console.log(location.hash); </script> </body>

测试效果如下图:


可以看到,通过改变锚点值,页面跳转到我们需要的内容.

再来看看VueRouter实现路由的控制:

<body> <div id="app"></div> <script>     // 第一步:在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Login = {         template: `             <div>                 <h1>我是登陆页面</h1>             </div>         `,     };     let Register = {         template: `             <div>                 <h1>我是注册页面</h1>             </div>         `,     };     let App = {         // 第四部:监听a标签的锚点值的改变         // 下面的router-link会渲染成a标签,to为标签的href属性,to后面是router中定义的路径         // 下面的router-view是页面内容的渲染出口         template: `             <div>                 <router-link to="/">首页</router-link>                 <router-link to="/login">登陆</router-link>                 <router-link to="/register">注册</router-link>                 <router-view></router-view>             </div>         `,     };     // 第二步:实例化一个router对象(本质上是将路径和页面绑定了对应关系)     let router = new VueRouter({         routes: [             // 注意:routes,不是routers             {                 path: '/',                 component: Home,             },             {                 path: '/login',                 component: Login,             },             {                 path: '/register',                 component: Register,             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 第三步:在根实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>

测试效果如下图:



路由命名

方式一:
==通过在vue-router对象中增加name属性来指定路由名称.==
==调用方式:v-bind:to={ name: "路由名称" }==

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Login = {         template: `         <div>             <h1>我是登陆页面</h1>         </div>         `,     };     let Register = {         template: `             <div>                 <h1>我是注册页面</h1>             </div>         `,     };     let App = {         // 下面的router-link会渲染成a标签,to为a标签的href属性,to后面的name指定的是路由别名         // 下面的router-view是页面内容的渲染出口         // 通过v-bind绑定定义的路由名称, v-bind:to="{ ... }", 可简写为:to="{ ... }"         template: `             <div>                 <router-link v-bind:to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'login' }">登陆</router-link>                 <router-link :to="{ name: 'register' }">注册</router-link>                 <router-view></router-view>             </div>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         // 注意:routes, 不是routers         routes: [             {                 // 路由命名                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'login',                 path: '/login',                 component: Login,             },             {                 name: 'register',                 path: '/register',                 component: Register,             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>

方式二:

<body> <div id="app"></div> <script>     Vue.use(VueRouter);     let App = {         template: `         <div>             <router-link to="/">首页</router-link>             <router-view name="header"></router-view>             <router-view name="footer"></router-view>         </div>     `,     };     let router = new VueRouter({         routes: [             {                 path: '/',                 components: {                     header: {                         template: `                             <div>头部</div>                         `,                     },                     footer: {                         template: `                             <div>底部</div>                         `,                     },                 },             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         router: router,         components: {             App,         },     }); </script> </body>


路由参数

<body> <div id="app"></div> <script>     /*     在真实的场景中,有以下两种路径形式:     1. xx.html/users/1     2. xx.html/users?userId=1     */     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是主页面</h1>             </div>         `,     };     let userParams = {         template: `             <div>                 <h1>我是用户1的信息</h1>             </div>         `,     };     let userQuery = {         template: `             <div>                 <h1>我是用户2的信息</h1>             </div>         `,     };     let App = {         // 下面的router-link会渲染成a标签,to为a标签的href属性,to后面的name指定的是路由别名         // 下面的router-view是页面内容的渲染出口         // 通过v-bind绑定路由名称, v-bind:to="{ ... }", 可简写为:to="{ ... }"         // 下面的params与query参数分别对应上面所说的两种路径形式         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'userParams', params: {userId: 1 } }">登陆</router-link>                 <router-link :to="{ name: 'userQuery', query: { userId: 2 } }">注册</router-link>                 <router-view></router-view>             </div>         `,     };     // 创建一个vue-router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 // 1. xx.html/users/1                 name: 'userParams',                 path: '/users/:userId',                 component: userParams,             },             {                 // 2. xx.html/users?userId=1                 name: 'userQuery',                 path: '/users',                 component: userQuery,             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在跟实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>

测试效果如下图:



***

路由参数的实现原理

<body> <div id="app"></div> <script>     /*     在真实的场景中,有以下两种路径形式:     1. xx.html/user/1     2. xx.html/user/?userId=1      */     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是主页面</h1>             </div>         `,     };     let userParams = {         template: `             <div>                 <h1>我是用户1的信息</h1>             </div>         `,         created () {             console.log('this.$route:', this.$route);             console.log('userId:', this.$route.params.userId);             // 此时可以发送ajax请求到后端获取数据         },     };     let userQuery = {         template: `             <div>                 <h1>我是用户2的信息</h1>             </div>         `,         created () {             console.log('this.$route:', this.$route);             console.log('userId:', this.$route.query.userId);             // 此时可以发送ajax请求到后端获取数据         }     };     let App = {         // 下面的router-link会渲染成a标签,to为a标签的href属性,to后面的name指定的是路由别名         // 下面的router-view是页面内容的渲染出口         // 通过v-bind绑定路由名称, v-bind:to="{ ... }", 可简写为:to="{ ... }"         // 下面params与query参数分别对应上面所说的两种路径形式         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'userParams', params: {userId: 1 } }">登陆</router-link>                 <router-link :to="{ name: 'userQuery', query: { userId: 2 } }">注册</router-link>                 <router-view></router-view>             </div>         `,     };     // 创建一个vue-router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 // 1. xx.html/user/1                 name: 'userParams',                 path: '/user/:userId',                 component: userParams,             },             {                 // 2. xx.html/user/?userId=1                 name: 'userQuery',                 path: '/user',                 component: userQuery,             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在跟实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>

测试效果如下图:




子路由

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Test = {         template: `             <div>                 <h1>我是测试页面</h1>                 <router-link to="childpages01">子页面01</router-link>                 <router-link to="childpages02">子页面02</router-link>                 <router-view></router-view>             </div>         `,     };     let ChildPages01 = {         template: `             <div>                 <h1>我是子页面01</h1>             </div>         `,     };     let ChildPages02 = {         template: `             <div>                 <h1>我是子页面02</h1>             </div>         `,     };     let App = {         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'test' }">测试页面</router-link>                 <router-view></router-view>             </div>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'test',                 path: '/courses',                 component: Test,                 // children实现子路由(子页面)                 children: [                     {                         path: 'childpages01',                         component: ChildPages01,                     },                     {                         path: 'childpages02',                         component: ChildPages02,                     },                 ],             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>

测试效果如下图:


可见,使用此方法,子页面不能正常显示.
***

子路由之append

==append参数会在路径后面追加子路由的路径,注意:会在后面一直追加.
append参数只适用于只需一层子路由的情况.==

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Test = {         // 添加append参数         template: `             <div>                 <h1>我是测试页面</h1>                 <router-link to="childpages01" append>子页面01</router-link>                 <router-link to="childpages02" append>子页面02</router-link>                 <router-view></router-view>             </div>         `,     };     let ChildPages01 = {         template: `             <div>                 <h1>我是子页面01</h1>             </div>         `,     };     let ChildPages02 = {         template: `             <div>                 <h1>我是子页面02</h1>             </div>         `,     };     let App = {         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'test' }">测试页面</router-link>                 <router-view></router-view>             </div>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'test',                 path: '/test',                 component: Test,                 // children实现子路由(子页面)                 children: [                     {                         path: 'childpages01',                         component: ChildPages01,                     },                     {                         path: 'childpages02',                         component: ChildPages02,                     },                 ],             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>

测试效果如下图:


这里只点击了一次 子页面01,显示的内容是正常的,后面的路径也是正常的.

下面的是点击了两次:


可见,内容显示不正常了,后面的路径也不正常了——==append参数会在后面一直添加子路由中的路径.==

使用以上方式,路径是写死在属性中的,所以子路径会不断的append到最后面,导致后续访问不到响应的页面,可以采用另一种方式——动态绑定属性.

动态绑定属性

==动态绑定属性即给子路由命名,使用子路由命的名称来实现子路径的正常切换.==

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Test = {         // 使用子路由命的名称来实现子路径的正常切换         template: `             <div>                 <h1>我是测试页面</h1>                 <router-link :to="{ name: 'childpages01' }">子页面01</router-link>                 <router-link :to="{ name: 'childpages02' }">子页面02</router-link>                 <router-view></router-view>             </div>         `,     };     let ChildPages01 = {         template: `             <div>                 <h1>我是子页面01</h1>             </div>         `,     };     let ChildPages02 = {         template: `             <div>                 <h1>我是子页面02</h1>             </div>         `,     };     let App = {         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'test' }">测试页面</router-link>                 <router-view></router-view>             </div>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'test',                 path: '/test',                 component: Test,                 // children实现子路由(子页面)                 children: [                     {                         // 给子路径命名                         name: 'childpages01',                         path: 'childpages01',                         component: ChildPages01,                     },                     {                         // 给子路径命名                         name: 'childpages02',                         path: 'childpages02',                         component: ChildPages02,                     },                 ],             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>

==注意:此方法必须使用name查找组件和路径的对应关系,而不能使用path.==
***

子路由之append升级版

==所谓的append升级版其实就是同时使用动态绑定属性和append.==

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Test = {         // append升级版:<router-link :to="{ name: 'childpages01' }" append>...</router-link>         template: `             <div>                 <h1>我是测试页面</h1>                 <router-link :to="{ name: 'childpages01' }" append>子页面01</router-link>                 <router-link :to="{ name: 'childpages02' }" append>子页面02</router-link>                 <router-view></router-view>             </div>         `,     };     let ChildPages01 = {         template: `             <div>                 <h1>我是子页面01</h1>             </div>         `,     };     let ChildPages02 = {         template: `             <div>                 <h1>我是子页面02</h1>             </div>         `,     };     let App = {         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'test' }">测试页面</router-link>                 <router-view></router-view>             </div>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'test',                 path: '/test',                 component: Test,                 // children实现子路由(子页面)                 children: [                     {                         // 给子路径命名                         name: 'childpages01',                         path: 'childpages01',                         component: ChildPages01,                     },                     {                         // 给子路径命名                         name: 'childpages02',                         path: 'childpages02',                         component: ChildPages02,                     },                 ],             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>

子路由之非append

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Test = {         template: `             <div>                 <h1>我是测试页面</h1>                 <router-link to="/test/childpages01">子页面01</router-link>                 <router-link to="/test/childpages02">子页面02</router-link>                 <router-view></router-view>             </div>         `,     };     let ChildPages01 = {         template: `             <div>                 <h1>我是子页面01</h1>             </div>         `,     };     let ChildPages02 = {         template: `             <div>                 <h1>我是子页面02</h1>             </div>         `,     };     let App = {         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'test' }">测试页面</router-link>                 <router-view></router-view>             </div>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'test',                 path: '/test',                 component: Test,                 // children实现子路由(子页面)                 children: [                     {                         // 子路由之非append(写全路径)                         path: '/test/childpages01',                         component: ChildPages01,                     },                     {                         // 子路由之非append(写全路径)                         path: '/test/childpages02',                         component: ChildPages02,                     },                 ],             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         },     }); </script> </body>


路由重定向

<body> <div id="app"></div> <script>     // // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);      let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Login = {         template: `             <div>                 <h1>我是登陆页面</h1>             </div>         `,     };     let Pay = {         template: `             <div>                 <h1>我是支付页面</h1>             </div>         `,     };     let App = {         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'login' }">登陆</router-link>                 <router-link :to="{ name: 'pay' }">支付</router-link>                 <router-view></router-view>             </div>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'login',                 path: '/login',                 component: Login,             },             {                 name: 'pay',                 path: '/pay',                 // 使用redirect实现路由重定向                 // 把a标签的锚点值和页面内容绑定了对应关系                 redirect: '/login',                 component: Pay,             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         }     }); </script> </body>

如上代码,我们点击支付链接时,将会跳转至登陆页面.

手动路由

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);      let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Test = {         template: `             <div>                 <h1>我是测试页面</h1>             </div>         `,     };     let App = {         // 使用v-on(简写为@)给按钮绑定一个事件         template: `             <div>                 <router-link to="/">首页</router-link>                 <button @click="myClick">点击跳转至测试页面</button>                 <router-view></router-view>             </div>         `,         // 定义一个用于跳转至测试页面的的事件         methods: {             myClick: function () {                 this.$router.push('/test');             }         },     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 path: '/',                 component: Home,             },             {                 path: '/test',                 component: Test,             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         }     }); </script> </body>

如上代码,点击按钮即可跳转至测试页面.

路由钩子

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Login = {         template: `             <div>                 <h1>我是登陆页面</h1>             </div>         `,     };     let Pay = {         template: `             <div>                 <h1>我是支付页面</h1>             </div>         `,     };     let App = {         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'login' }">登陆</router-link>                 <router-link :to="{ name: 'pay' }">支付</router-link>                 <router-view></router-view>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'login',                 path: '/login',                 component: Login,             },             {                 name: 'pay',                 path: '/pay',                 // 这一步骤将调用路由钩子函数(通过布尔值来判断是否调用该钩子函数)                 meta: {required_login: true},                 component: Pay,             },         ],     });     // 定义一个路由钩子函数     // 通过router对象的beforeEach(function (to, form, next) {})     router.beforeEach(function (to, from, next) {         // to:从哪来         // from:到哪去         // next:下一步做什么         console.log('to:', to);         console.log('from:', from);         console.log('next:', next);         if (to.meta.required_login) {             next('/login');         } else {             next();  // 正常跳转         }     // router.afterEach(function (to, from) { ··· });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         }     }); </script> </body>

如上代码,通过路由钩子函数实现了点击支付链接时跳转至登陆页面的功能.

在路径中去掉"#"号

在实例化的router对象中增加一个属性:==mode: 'history'==,该属性可将路径中显示的"#"号去掉.

<body> <div id="app"></div> <script>     // 在Vue根实例中使用VueRouter     Vue.use(VueRouter);     let Home = {         template: `             <div>                 <h1>我是首页</h1>             </div>         `,     };     let Login = {         template: `             <div>                 <h1>我是登陆页面</h1>             </div>         `,     };     let Pay = {         template: `             <div>                 <h1>我是支付页面</h1>             </div>         `,     };     let App = {         template: `             <div>                 <router-link :to="{ name: 'home' }">首页</router-link>                 <router-link :to="{ name: 'login' }">登陆</router-link>                 <router-link :to="{ name: 'pay' }">支付</router-link>                 <router-view></router-view>         `,     };     // 实例化一个router对象(本质上是将路径和页面内容绑定了对应关系)     let router = new VueRouter({         // 使用mode: 'history'实现取去掉路径中显示的"#"号         mode: 'history',         routes: [             {                 name: 'home',                 path: '/',                 component: Home,             },             {                 name: 'login',                 path: '/login',                 component: Login,             },             {                 name: 'pay',                 path: '/pay',                 component: Pay,             },         ],     });     new Vue({         el: '#app',         template: `<App/>`,         // 在根实例中注册router对象         router: router,         components: {             App,         }     }); </script> </body>


原文: http://blog.gqylpy.com/gqy/280

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!