路由的基本概念与原理
路由介绍
-
路由是一个比较广义和抽象的概念,路由的本质就是一一对应关系
-
开发中路由分两种
- 前端路由
- 后端路由
-
路由的本质就是一种对应关系,比如:在地址栏中输入url地址,获取对应的url资源
-
路由分为前端路由和后端路由
- 前端路由是依靠hash值(也就是a标签的锚点连接)的变化进行实现(锚点与组件之间的关系)
- 前端路由的基本概念:根据不同的事件来显示不同的页面内容,事件与事件处理函数之间的对应关系
- 前端路由主要做的事情就是监听事件,执行对应的事件处理函数
- 后端路由是由服务器端实现的,并完成资源的分发(url与资源数据的对应关系)
- 后端路由性能相对前端路由来说较低
后端路由
-
后端路由介绍
-
总结
- 后端 渲染页面,只要修改一处,就需要刷新整个页面,存在性能问题
- Ajax是一种局部更新网页的技术,但是不支持前进后退
前端 路由
-
前端路由介绍
- 根据地址栏的变化(不发送Ajax请求),去局部更新页面内容
- 前端业务场景切换
-
前端-实现原理
-
地址栏中的
#
有两个含义-
锚点链接:在当前页面进行页面跳转
-
哈希值(hash)的作用,当它发生变化时不会刷新当前页面,但是它的变化会触发hashchange事件,
核心实现依靠hashchang事件,即监听hash值变化的事件
window.onhashchange = function(){ //location.hash可以获取到最新的hash值 location.hash }
-
-
-
总结
- 路由:一种一一对应关系,请求url地址与url资源的一一对应
- 后端路由:url与服务资源的一一对应关系
- 前端路由:用户事件与事件处理函数的一一对应关系 比如点击页面的按钮改变url的hash值,根据hash值的变化来切换组件
SPA
-
SPA介绍
- 单页面应用程序,简称SPA(single page application)一个项目的所有功能在一个页面上实现,(在移动端比较多,只要是用Vue开发的项目,绝大多数是SPA)
- SPA实现原理之一:基于URL地址的hash值(hash的变化会导致浏览器记录访问历史的变化 ,但是hash的变化不会触发新的url请求)
- SPA是通过前端路由实现业务场景的切换的。
- SPA可以局部更新,也支持前进后退
- 使用vue-router可以轻易的实现前端路由业务
-
特点
- 优点: 整体不刷新页面,用户体验更好
- 缺点:首次加载会比较慢一点,后面会有优化的方式
Vue-router的基本使用
-
介绍
- Vue.js官方提供了路由管理器,是一个功能强大的前端路由器,推荐使用
- Vue Router和Vue.js非常契合,可以一起方便的实现SPA(single page web application,单页应用程序)应用程序的开发
- vue Router依赖vue.js,必须先引入vue.js再引入vue Router
- Vue Router 官网 router.vuejs.org/zh/
-
Vue Router的特性
- 支持H5历史模式或者hash模式
- 支持嵌路由
- 支持路由参数
- 支持编程式路由
- 支持命名路由
- 导航守卫
- 路由懒加载
- 过渡动效
- ................
使用步骤
-
引入 Vue router 文件( 在此之前必须先引入 vue.js文件)
-
添加路由链接
-
添加路由点位符(最后路由展示的组件就会在点位符的位置显示 )
-
定义路由组件
-
配置路由规则并创建路由实例
-
将路由挂载到Vue实例中
-
引入Vue router
<!-- 导入vue文件,为全局window对象挂载Vue构造函数 --> <script src="./lib/vue_2.5.22.js"></script> <!-- 导入vue-router文件,为全局window对象挂载VueRouter构造函数 --> <script src="./lib/vue-router_3.0.2.js"></script>
-
添加路由连接
<!--router-link是路由提供的标签,默认会被渲染为a标签--> <!--to属性默认被渲染为href属性--> <!--to属性的值会被渲染为#开头的hash地址--> <router-link to="/user">User</router-link>
-
添加路由占位符
<!--将来通过路由规则匹配到的组件,将会被渲染到router-view所在的位置--> <router-view></router-view>
- router-view:路由-视图,用户点击路由链接显示对应的组件
-
定义路由组件
var User = { template:"<div>This is User</div>" } var Login = { template:"<div>This is Login</div>" }
-
创建路由实例,并配置路由规则
//创建路由实例对象 var router = new VueRouter({ //routes是路由规则数组 routes:[ //每一个路由规则都是一个对象,对象中至少包含path和component两个属性 //path表示 路由匹配的hash地址, //component表示路由规则对应要展示的组件对象 {path:"/user",component:User}, {path:"/login",component:Login} ] })
-
将路由挂载到Vue实例中
//将路由挂载到Vue实例中 new Vue({ el:"#app", //为了让路由规则生效,必须把路由对象挂载到Vue实例上 router })
- Vue实例化时参数el,data,methods,router都是固定的
路由重定向
-
路由重定向指的是:用户在访问地址A的时候,强制用户跳转到地址c,从而展示特定的组件页面:通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由的重定向
var router = new VueRouter({ //routes是路由规则数组 routes: [ //path设置为/表示页面最初始的地址 / ,redirect表示要被重定向的新地址,设置为一个路由即可 { path:"/",redirect:"/user"}, { path: "/user", component: User }, { path: "/login", component: Login } ] })
- 应用:打开页面时默认访问的是#/根地址,我希望打开页面就能访问:#/user,所以使用重写向
路由-404页面
-
当我们访问一个不存在的页面,给出一个提示,让用户访问404页面
-
思路:其它的路由规则都没有匹配成功,用
*
来匹配保底 -
格式:
{ path: '*', component: { template: '<div>你要找的页面,被外星人吃掉了~~~</div>' } }
const router = new VueRouter({ // routes: 配置路由规则 routes: [ // * 表示全部 , 实现404页 // 其它规则都没有匹配成功,就到这里来 { path: '*', component: { template: '<div>你要找的页面,被外星人吃掉了 ~~~</div>' } } ] })
嵌套路由
-
点击父级路由链接显示模板内容,模板内容中又有子路由,点击子路由显示对应的内容
-
比如我们有一个Login的父路由可以添加子路由/login/account与/login/phone
<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> <script src="./lib/vue-router_3.0.2.js"></script> </head> <body> <!-- 被 vm 实例所控制的区域 --> <div id="app"> <router-link to="/user">User</router-link> <router-link to="/register">Register</router-link> <!-- 路由占位符 --> <router-view></router-view> </div> <script> const User = { template: '<h1>User 组件</h1>' } const Register = { template: `<div> <h1>Register 组件</h1> <hr/> <!-- 子路由链接 --> <router-link to="/register/tab1">tab1</router-link> <router-link to="/register/tab2">tab2</router-link> <!-- 子路由的占位符 --> <router-view /> <div>` } //定义两个子级路由组件 const Tab1 = { template: '<h3>tab1 子组件</h3>' } const Tab2 = { template: '<h3>tab2 子组件</h3>' } // 创建路由实例对象 const router = new VueRouter({ // 所有的路由规则 routes: [ { path: '/', redirect: '/user'}, { path: '/user', component: User }, // children 数组表示子路由规则 { path: '/register', component: Register, children: [ { path: '/register/tab1', component: Tab1 }, { path: '/register/tab2', component: Tab2 } ] } ] }) // 创建 vm 实例对象 const vm = new Vue({ // 指定控制的区域 el: '#app', data: {}, // 挂载路由实例对象 // router: router router }) </script> </body>
-
总结:
- 子路由规则在父路由规则中定义,router-view和router-link就写在父路由模板中
vue-router动态路由匹配
动态路由匹配
-
应用场景:通过动态路由参数的模式进行路由匹配
<body> <!-- 被 vm 实例所控制的区域 --> <div id="app"> <router-link to="/user/1">User1</router-link> <router-link to="/user/2">User2</router-link> <router-link to="/user/3">User3</router-link> <router-link to="/register">Register</router-link> <!-- 路由占位符 --> <router-view></router-view> </div> <script> //组件 const User={ //路由组件中通过$route.params获取路由参数 template:'<div>用户:{{$route.params.id}}</div>' } var router = new VueRouter({ //routes是路由规则数组 routes: [ //通过/:参数名的形式传递参数 { path: "/user/:id", component: User }, ] }) // 创建 vm 实例对象 const vm = new Vue({ // 指定控制的区域 el: '#app', data: {}, // 挂载路由实例对象 // router: router router }) </script> </body>
-
匹配规则定义时,动态路由语法为**:参数名**,以冒号开头,就代表是动态匹配
-
路由组件定义时,获取路由参数为:{{$route.params.参数名}}
-
动态获取路由参数{{$route.params.}}是固定写法
-
props传递参数
-
介绍props
- $route.params与对应路由形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦
- props的使用分三类 :props的值为,布尔类型,对象类型,函数类型
-
props的值为布尔类型
var User = { props:["id"], //使用props 接收路由参数 template:"<div>用户:{{id}}</div>" //使用路由参数 } var myRouter = new VueRouter({ //routes是路由规则数组 routes: [ //通过/:参数名 的形式传递参数 //如果props设置为true,route.params将会被设置为组件属性 { path: "/user/:id", component: User,props:true }, ]
- 路由定义规则中:props:true,true代表开启props传递动态参数
- 路由组件定义中:通过props接收参数
-
props的值为对象类型
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} } ] })
- username的jacki传递给User组件中props的username,pwd的123传递给User组件中props的pwd
- 这时的id就无法获取了,所以id在这种方式中就废了
- 只有props为true时,才会将:id作为参数传递给User
-
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} } } ] })
- 箭头函数返回一个对象,对象中的数据就是要传递的数据
- id通过 route.params.id动态获取到id参数的值
### query查询传参
- 查询传参 :this.$router.query.id
```js
//参数 id=1&age=3
<router-link to="/user?id=1&age=3">query查询传参</router-link>
var User = { // $route.query获取的是一个对象 ,在路由链接中查询参数
template: ` <div> {{$route.query.id}} - {{$route.query.age}}</div>`
}
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
{ path: "/user", component: User }
]
})
命名路由与编程式导航
###命名路由
- 为了更加方便的表示路由的路径,可以给路由规则 起一个别名,即为 “命名路由”
//路由链接
<router-link :to="{ name:'user' , params: {id:123} }">User</router-link>
const router = new VueRouter({
//routes是路由规则数组
routes: [
//通过name属性为路由添加一个别名
{
path: "/user/:id",
component: User,
name:"user" //命名路由
},
]
})
- 有时候path比较复杂,用命名路由代替会更好一点
- 如果path中有参数,那么在to中就通过params来确定参数的值
编程式导航
-
页面导航的两种方式
-
声明式导航:通过点击链接实现导航的方式,叫做声明式导航
例如 普通网页中的
<a></a>
链接或vue中的<router-link></router-link>
-
编程式导航:通过调用javaScript形式的APl实现导航的方式,叫做编程式导航
例如:普通网页中的location.href
- 声明式导航:其实就是html实现导航
- 编程式导航:其实就是js代码实现导航(location.href 就是js代码)
- 编程式路由跳转:
this.$router.push("/register")
-
-
编程导航
-
常用的编程式导航API
this.$router.push(hash地址) //根据hash值跳转到对应的组件上 this.$router.go(n) // 前进后退功能 n表示数值 '-1'后退 '1' 前进
cons User={ template:'<div><button @click="goRegister">跳转到注册页面</button></div>' methods:{ goRegister:function(){ //用编程的方式控制路由跳转 this.$router.push("/register"); } } }
- push跳转锚点
- go前进后退,参数n一个数字,代表前进后退几个界面
- n,代表前进n个界面
- -n,代表后退n个界面
-
push参数 (了解)
-
介绍
-
跟route-link是一样的作用,都是实现页面跳转
-
所以push中可以直接写path路径(路由),也可以写命名路由
-
相当于:
<!--前两个对应这个 --> <router-link to="/home">User1</router-link> <!--#push中的name应该也不带斜杠才对--> <!--命名路由(传递参数)--> <router-link :to="{ name: 'user', params: {userId: 123} }">User123</router-link> <!--带查询参数,变成 register?uname=lisi --> <router-link to="/register?uname=lisi">Register</router-link>
导航守卫
-
在路由跳转之后加一层拦截做一些我们自己的事
-
实际应用场景:登录
- 如果当前登录了,我就让你跳到列表页l 如果没登录 那我就提示你登录,并且不让你跳转 特点:在发生路由跳转行为的时候,会调用回调函数 这个就是导航守卫
router.beforeEach((to, from, next) => { console.log('当前路由跳转了') next() }) // to: 代表的是目标路由对象 detail路由对象 // from: 代表的是路由跳转的来源对象 list路由对象 // next: next函数的执行决定了能不能跳转 如果不调用会产生一种 ‘守死了’ // 模拟登陆校验 const loginFlag = false router.beforeEach((to, from, next) => { // 判断当前是否登录 loginFlag true 登录 false 没登录 if (!loginFlag) { // 如果没登录就提示登录 alert('请先登录!') } else { // 如果登录了就跳转 next() } })
「点赞、收藏和评论」
❤️关注+点赞+收藏+评论+转发❤️,鼓励笔者创作更好的文章,谢谢?大家。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!