一.路由的概念与原理
路由的实质就是一种对应关系,比方咱们在url地址中输出咱们要拜访的url地址之后,浏览器要去申请这个url地址对应的资源。
那么url地址和实在的资源之间就有一种对应的关系,就是路由。
路由分为前端路由和后端路由
1.1 后端路由
后端路由是依据不同的用户URL申请,返回不同的内容,实质就是URL申请地址与服务器资源之间的对应关系。
由服务器端进行实现,并实现资源的散发。
1.2 前端路由
前端路由依附hash值(锚链接)的变动进行实现。
后端路由性能绝对前端路由来说较低,所以,咱们接下来次要学习的是前端路由。
基本概念:依据不同的事件来显示不同的页面内容,即用户事件与事件处理函数之间的对应关系。
前端路由次要做的事件就是监听事件并散发执行事件处理函数。
1.3 SPA(Single Page Application)
- 后端渲染(存在性能问题)
- Ajax前端渲染(前端渲染进步性能,然而不反对浏览器的后退操作)
- SPA单页面应用程序:整个网站只有一个页面,内容的变动通过Ajax部分更新实现,同时反对浏览器地址栏的后退和后退操作
- SPA的实现原理之一:基于URL地址的hash(hash的变动会导致浏览器拜访历史记录的变动,但hash的变动不会触发新的URL申请)
- 在实现SPA的过程中,最外围的技术点就是前端路由
二、前端路由的初体验
前端路由是基于hash值的变动进行实现的(比方点击页面中的菜单或者按钮扭转URL的hash值,依据hash值的变动来管制组件的切换)
外围实现依附一个事件,即监听hash值变动的事件
window.onhashchange = function(){ //location.hash能够获取到最新的hash值 location.hash}
前端路由实现tab栏切换:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> <!-- 导入 vue 文件 --> <script src="./lib/vue_2.5.22.js"></script></head><body> <!-- 被 vue 实例管制的 div 区域 --> <div id="app"> <!-- 切换组件的超链接 --> <a href="#/zhuye">主页</a> <a href="#/keji">科技</a> <a href="#/caijing">财经</a> <a href="#/yule">娱乐</a> <!-- 依据 :is 属性指定的组件名称,把对应的组件渲染到 component 标签所在的地位 --> <!-- 能够把 component 标签当做是【组件的占位符】 --> <component :is="comName"></component> </div> <script> // #region 定义须要被切换的 4 个组件 // 主页组件 const zhuye = { template: '<h1>主页信息</h1>' } // 科技组件 const keji = { template: '<h1>科技信息</h1>' } // 财经组件 const caijing = { template: '<h1>财经信息</h1>' } // 娱乐组件 const yule = { template: '<h1>娱乐信息</h1>' } // #endregion // #region vue 实例对象 const vm = new Vue({ el: '#app', data: { comName: 'zhuye' }, // 注册公有组件 components: { zhuye, keji, caijing, yule } }) // #endregion // 监听 window 的 onhashchange 事件,依据获取到的最新的 hash 值,切换要显示的组件的名称 window.onhashchange = function() { // 通过 location.hash 获取到最新的 hash 值 console.log(location.hash); // #/zhuye vm.comName = location.hash.slice(2) } </script></body></html>
案例效果图:
点击每个超链接之后,会进行相应的内容切换,如下:
外围思路:
在页面中有一个vue实例对象,vue实例对象中有四个组件,别离是tab栏切换须要显示的组件内容
在页面中有四个超链接,如下:
<a href="#/zhuye">主页</a> <a href="#/keji">科技</a> <a href="#/caijing">财经</a><a href="#/yule">娱乐</a>
当咱们点击这些超链接的时候,就会扭转url地址中的hash值,当hash值被扭转时,就会触发onhashchange事件,而后失去以后hash值,依据这个hash值来让不同的组件进行显示。
三、Vue Router简介
它是一个Vue.js官网提供的路由管理器。是一个性能更加弱小的前端路由器,举荐应用。
Vue Router和Vue.js的外围深度集成,因而十分符合,能够一起不便的实现SPA单页应用程序的开发。
Vue Router依赖于Vue,所以须要先引入Vue,再引入Vue Router
Vue Router的个性:
- 反对H5历史模式或者hash模式
- 反对嵌套路由
- 反对路由参数
- 反对编程式路由
- 反对命名路由
- 反对路由导航守卫
- 反对路由过渡动画特效
- 反对路由懒加载
- 反对路由滚动行为
四、Vue Router的应用步骤(★★★)
A.导入js文件<script src="lib/vue_2.5.22.js"></script>
为全局window对象挂载VueRouter构造函数<script src="lib/vue-router_3.0.2.js"></script>
B.增加路由链接<router-link>
是vue中提供的标签,默认会被渲染为a标签,
to属性默认被渲染为href属性,
to属性的值会被渲染为#结尾的hash地址<router-link to="/user">User</router-link>
<router-link to="/login">Login</router-link>
C.增加路由填充位(路由占位符)<router-view></router-view>
最初路由展现的组件就会在占位符的地位显示
D.定义路由组件var User = { template:"<div>This is User</div>" }
var Login = { template:"<div>This is Login</div>" }
E.配置路由规定并创立路由实例
var myRouter = new VueRouter({ //routes是路由规定数组 routes:[ //每一个路由规定都是一个对象,对象中至多蕴含path和component两个属性 //path示意 路由匹配的hash地址,component示意路由规定对应要展现的组件对象 {path:"/user",component:User}, {path:"/login",component:Login} ]})
F.将路由挂载到Vue实例中
new Vue({ el:"#app", //通过router属性挂载路由对象 router:myRouter})
补充:
路由重定向:能够通过路由重定向为页面设置默认展现的组件
在路由规定中增加一条路由规定即可,如下:
var myRouter = new VueRouter({ //routes是路由规定数组 routes: [ //path设置为/示意页面最初始的地址 / ,redirect示意要被重定向的新地址,设置为一个路由即可 { path:"/", redirect:"/user"}, { path: "/user", component: User }, { path: "/login", component: Login } ]})
五、嵌套路由,动静路由的实现形式
A.嵌套路由的概念(★★★)
当咱们进行路由的时候显示的组件中还有新的子级路由链接以及内容。
嵌套路由最要害的代码在于了解子级路由的概念:
比方咱们有一个/login的路由
那么/login上面还能够增加子级路由,如:
/login/account
/login/phone
参考代码如下:
var User = {template: "<div>This is User</div>"} //Login组件中的模板代码外面蕴含了子级路由链接以及子级路由的占位符 var Login = { template: `<div> <h1>This is Login</h1> <hr> <router-link to="/login/account">账号密码登录</router-link> <router-link to="/login/phone">扫码登录</router-link> <router-view></router-view> </div>` } //定义两个子级路由组件 var account = {template: "<div>账号:<input><br>明码:<input></div>"}; var phone = {template: "<h1>扫我二维码</h1>"}; var myRouter = new VueRouter({ //routes是路由规定数组 routes: [ {path: "/", redirect: "/user"}, {path: "/user", component: User}, { path: "/login", component: Login, //通过children属性为/login增加子路由规定 children: [ {path: "/login/account", component: account}, {path: "/login/phone", component: phone}, ] } ] }) var vm = new Vue({ el: '#app', data: {}, methods: {}, router: myRouter });
页面成果大抵如下:
B.动静路由匹配(★★★)
<router-link to="/user/22">User</router-link>
var User = { template:"<div>用户:{{$route.params.id}}</div>"}var myRouter = new VueRouter({ //routes是路由规定数组 routes: [ //通过 /:参数名 的模式传递参数 { path: "/user/:id", component: User }, ]})
能够在路由对应的组件中应用$route.params.id
来获取门路传参的id参数值,然而这种形式不够灵便。今后能够尽量应用props将组件和路由解耦。
1.通过props来接管参数
var User = { props:["id"], //应用props接管id参数 template:"<div>用户:{{id}}</div>"}var myRouter = new VueRouter({ //routes是路由规定数组 routes: [ //通过/:参数名 的模式传递参数 //如果props设置为true,route.params将会被设置为组件属性 { path: "/user/:id", component: User, props:true }, ]})
2.还有一种状况,咱们能够将props设置为对象,间接将静态数据传递给组件进行应用。
然而这样id的值就拜访不到了。
var User = { props:["username","pwd"], template:"<div>用户:{{username}}---{{pwd}}</div>" }var myRouter = new VueRouter({ //routes是路由规定数组 routes: [ //通过 /:参数名 的模式传递参数 //如果props设置为对象,则传递的是对象中的数据给组件 { path: "/user/:id", component: User, props:{username:"jack",pwd:123} }, ]})
3.如果既想要获取路由传递的参数值,又想获取传递的对象数据,那么props应该设置为函数模式。
var User = { props:["username","pwd","id"], template:"<div>用户:{{id}} -> {{username}}---{{pwd}}</div>" }var myRouter = new VueRouter({ //routes是路由规定数组 routes: [ //通过 /:参数名 的模式传递参数 //如果props设置为函数,则通过函数的第一个参数获取路由对象 //并能够通过路由对象的params属性获取传递的参数 // { path: "/user/:id", component: User,props:(route)=>{ return {username:"jack",pwd:123,id:route.params.id} } }, ]})
六、命名路由以及编程式导航
A.命名路由:用name属性值给路由取别名
案例:
var User = { template:"<div>用户:{{$route.params.id}}</div>"}var myRouter = new VueRouter({ //routes是路由规定数组 routes: [ //通过name属性为路由增加一个别名 { path: "/user/:id", component: User, name:"user"}, ]})
增加了别名之后,能够应用别名进行跳转(给to属性绑定对象的模式)<router-link to="/user/123">User</router-link>
等价于<router-link :to="{ name:'user' , params: {id:123} }">User</router-link>
还能够编程式导航myRouter.push( { name:'user' , params: {id:123} } )
var vm = new Vue({ el: '#app', data: {}, methods: {}, router: myRouter, mounted:function () { myRouter.push( { name:'user' , params: {id:123} } ) } });
B.编程式导航(★★★)
页面导航的两种形式:
A.申明式导航:通过点击链接的形式实现的导航
B.编程式导航:调用js的api办法实现导航,比方调用location.href
就是
Vue-Router中常见的导航形式:this.$router.push("hash地址");
this.$router.push("/login");
this.$router.push({ name:'user' , params: {id:123} });
this.$router.push({ path:"/login" });
this.$router.push({ path:"/login",query:{username:"jack"} });
this.$router.go(n);
n为数字,参考history.gothis.$router.go(-1);
七、实现后盾治理案例(★★★)
案例成果:
点击左侧的"用户治理","权限治理","商品治理","订单治理","零碎设置"都会呈现对应的组件并展现内容
其中"用户治理"组件展现的成果如上图所示,在用户治理区域中的详情链接也是能够点击的,点击之后将会显示用户详情信息。
案例思路:
1).先将以下代码
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>基于vue-router的案例</title> <style type="text/css"> html, body, #app { margin: 0; padding: 0px; height: 100%; } .header { height: 50px; background-color: #545c64; line-height: 50px; text-align: center; font-size: 24px; color: #fff; } .footer { height: 40px; line-height: 40px; background-color: #888; position: absolute; bottom: 0; width: 100%; text-align: center; color: #fff; } .main { display: flex; position: absolute; top: 50px; bottom: 40px; width: 100%; } .content { flex: 1; text-align: center; height: 100%; } .left { flex: 0 0 20%; background-color: #545c64; } .left a { color: white; text-decoration: none; } .right { margin: 5px; } .btns { width: 100%; height: 35px; line-height: 35px; background-color: #f5f5f5; text-align: left; padding-left: 10px; box-sizing: border-box; } button { height: 30px; background-color: #ecf5ff; border: 1px solid lightskyblue; font-size: 12px; padding: 0 20px; } .main-content { margin-top: 10px; } ul { margin: 0; padding: 0; list-style: none; } ul li { height: 45px; line-height: 45px; background-color: #a0a0a0; color: #fff; cursor: pointer; border-bottom: 1px solid #fff; } table { width: 100%; border-collapse: collapse; } td, th { border: 1px solid #eee; line-height: 35px; font-size: 12px; } th { background-color: #ddd; } </style> </head> <body> <div> <!-- 头部区域 --> <header class="header">后盾管理系统</header> <!-- 两头主体区域 --> <div class="main"> <!-- 左侧菜单栏 --> <div class="content left"> <ul> <li>用户治理</li> <li>权限治理</li> <li>商品治理</li> <li>订单治理</li> <li>零碎设置</li> </ul> </div> <!-- 右侧内容区域 --> <div class="content right"><div class="main-content">增加用户表单</div></div> </div> <!-- 尾部区域 --> <footer class="footer">版权信息</footer> </div> </body></html>
复制到咱们本人的文件夹中。
看一下这个文件中的代码编写了一些什么内容,
这个页面曾经把后盾治理页面的根本布局实现了
2).在页面中引入vue,vue-router
3).创立Vue实例对象,筹备开始编写代码实现性能
4).心愿是通过组件的模式展现页面的主体内容,而不是写死页面构造,所以咱们能够定义一个根组件:
//只须要把本来页面中的html代码设置为组件中的模板内容即可const app = { template:`<div> <!-- 头部区域 --> <header class="header">后盾管理系统</header> <!-- 两头主体区域 --> <div class="main"> <!-- 左侧菜单栏 --> <div class="content left"> <ul> <li>用户治理</li> <li>权限治理</li> <li>商品治理</li> <li>订单治理</li> <li>零碎设置</li> </ul> </div> <!-- 右侧内容区域 --> <div class="content right"> <div class="main-content">增加用户表单</div> </div> </div> <!-- 尾部区域 --> <footer class="footer">版权信息</footer> </div>` }
5).当咱们拜访页面的时候,默认须要展现刚刚创立的app根组件,咱们能够
创立一个路由对象来实现这个事件,而后将路由挂载到Vue实例对象中即可
const myRouter = new VueRouter({ routes:[ {path:"/",component:app} ]})const vm = new Vue({ el:"#app", data:{}, methods:{}, router:myRouter})
补充:到此为止,根本的js代码都处理完毕了,咱们还须要设置一个路由占位符
<body> <div id="app"> <router-view></router-view> </div></body>
6).此时咱们关上页面应该就能够失去一个VueRouter路由进去的根组件了
咱们须要在这个根组件中持续路由实现其余的性能子组件
先让咱们更改根组件中的模板:更改左侧li为子级路由链接,并在右侧内容区域增加子级组件占位符
const app = { template:`<div> ........ <div class="main"> <!-- 左侧菜单栏 --> <div class="content left"> <ul> <!-- 留神:咱们把所有li都批改为了路由链接 --> <li><router-link to="/users">用户治理</router-link></li> <li><router-link to="/accesses">权限治理</router-link></li> <li><router-link to="/goods">商品治理</router-link></li> <li><router-link to="/orders">订单治理</router-link></li> <li><router-link to="/systems">零碎设置</router-link></li> </ul> </div> <!-- 右侧内容区域 --> <div class="content right"> <div class="main-content"> <!-- 在 --> <router-view></router-view> </div> </div> </div> ....... </div>` }
而后,咱们要为子级路由创立并设置须要显示的子级组件
//倡议创立的组件首字母大写,和其余内容辨别const Users = {template:`<div> <h3>用户治理</h3></div>`}const Access = {template:`<div> <h3>权限治理</h3></div>`}const Goods = {template:`<div> <h3>商品治理</h3></div>`}const Orders = {template:`<div> <h3>订单治理</h3></div>`}const Systems = {template:`<div> <h3>系统管理</h3></div>`}//增加子组件的路由规定const myRouter = new VueRouter({ routes:[ {path:"/",component:app , children:[ { path:"/users",component:Users }, { path:"/accesses",component:Access }, { path:"/goods",component:Goods }, { path:"/orders",component:Orders }, { path:"/systems",component:Systems }, ]} ]})const vm = new Vue({ el:"#app", data:{}, methods:{}, router:myRouter})
7).展现用户信息列表:
A.为Users组件增加公有数据,并在模板中循环展现公有数据
const Users = { data(){ return { userList:[ {id:1,name:"zs",age:18}, {id:2,name:"ls",age:19}, {id:3,name:"wang",age:20}, {id:4,name:"jack",age:21}, ] } }, template:`<div> <h3>用户治理</h3> <table> <thead> <tr> <th>编号</th> <th>姓名</th> <th>年龄</th> <th>操作</th> </tr> </thead> <tbody> <tr :key="item.id" v-for="item in userList"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.age}}</td> <td><a href="javascript:;">详情</a></td> </tr> </tbody> </table> </div>`}
8.当用户列表展现结束之后,咱们能够点击列表中的详情来显示用户详情信息,首先咱们须要创立一个组件,用来展现详情信息
const UserInfo = { props:["id"], template:`<div> <h5>用户详情</h5> <p>查看 {{id}} 号用户信息</p> <button @click="goBack">返回用户详情页</button> </div> `, methods:{ goBack(){ //当用户点击按钮,后退一页 this.$router.go(-1); } } }
而后咱们须要设置这个组件的路由规定
const myRouter = new VueRouter({ routes:[ {path:"/",component:app , children:[ { path:"/users",component:Users }, //增加一个/userinfo的路由规定 { path:"/userinfo/:id",component:UserInfo,props:true}, { path:"/accesses",component:Access }, { path:"/goods",component:Goods }, { path:"/orders",component:Orders }, { path:"/systems",component:Systems }, ]} ]})const vm = new Vue({ el:"#app", data:{}, methods:{}, router:myRouter})
再接着给用户列表中的详情a连贯增加事件
const Users = { data(){ return { userList:[ {id:1,name:"zs",age:18}, {id:2,name:"ls",age:19}, {id:3,name:"wang",age:20}, {id:4,name:"jack",age:21}, ] } }, template:`<div> <h3>用户治理</h3> <table> <thead> <tr> <th>编号</th> <th>姓名</th> <th>年龄</th> <th>操作</th> </tr> </thead> <tbody> <tr :key="item.id" v-for="item in userList"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.age}}</td> <td><a href="javascript:;" @click="goDetail(item.id)">详情</a></td> </tr> </tbody> </table> </div>`, methods:{ goDetail(id){ this.$router.push("/userinfo/"+id); } }}