今日目标:
1.能够说出什么是路由
2.能够说出前端路由的实现原理
3.能够使用Vue-Router实现前端路由
4.能够实现嵌套路由,动态路由
5.能够实现命名路由以及编程式导航
6.理解并实现后台管理案例
1.路由的基本概念与原理
1.1 路由
- 路由的本质就
是一种对应关系
,比如说我们在url地址中输入我们要访问的url地址之后,浏览器要去请求这个url地址对应的资源。那么url地址和真实的资源之间就有一种对应的关系,就是路由。
路由分为前端路由和后端路由
- 后端路由是由服务器端进行实现,并完成资源的分发
- 前端路由是依靠hash值(锚链接)的变化进行实现
1. 后端路由
- 概念:根据不同的
用户 URL
请求,返回不同的内容 - 本质:
URL 请求地址
与服务器资源
之间的对应关系
2.前端路由
前端路由的基本概念:
- 根据不同的事件来显示不同的页面内容,即
事件与事件处理函数之间
的对应关系
- 前端路由主要做的事情就是
监听事件
并分发执行事件处理函数
3. SPA(Single Page Application)
- 后端渲染(存在性能问题)
- Ajax前端渲染(前端渲染提高性能,但是不支持浏览器的前进后退操作)
- SPA(Single Page Application)单页面应用程序:整个网站只有一个页面,内
容的变化通过Ajax局部更新实现、同时支持浏览器地址栏的前进和后退操作 SPA实现原理之一
:基于URL地址的hash(hash的变化会导致浏览器记录访问历 史的变化、但是hash的变化不会触发新的URL请求)- 在实现SPA过程中,最核心的技术点就是前端路由
4. 实现简易前端路由
- 前端路由是基于hash值的变化进行实现的(比如点击页面中的菜单或者按钮改变URL的hash值,根据hash值的变化来控制组件的切换)核心实现依靠一个事件,即监听hash值变化的事件
// 监听 window 的 onhashchange 事件,根据获取到的最新的 hash 值,切换要显示的组件的名称
window.onhashchange = function() {
// 通过 location.hash 获取到最新的 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);
switch(location.hash.slice(1)){
case '/zhuye':
vm.comName = 'zhuye'
break
case '/keji':
vm.comName = 'keji'
break
case '/caijing':
vm.comName = 'caijing'
break
case '/yule':
vm.comName = 'yule'
break
}
}
</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事件
在触发onhashchange事件的时候,我们根据hash值来让不同的组件进行显示:
window.onhashchange = function() {
// 通过 location.hash 获取到最新的 hash 值
console.log(location.hash);
switch(location.hash.slice(1)){
case '/zhuye':
//通过更改数据comName来指定显示的组件
//因为 <component :is="comName"></component> ,组件已经绑定了comName
vm.comName = 'zhuye'
break
case '/keji':
vm.comName = 'keji'
break
case '/caijing':
vm.comName = 'caijing'
break
case '/yule':
vm.comName = 'yule'
break
}
}
1.2Vue Router简介
- Vue Router(官网:https://router.vuejs.org/zh/)是 Vue.js 官方的路由管理器。
- 它和 Vue.js 的核心深度集成,可以非常方便的用于SPA应用程序的开发
- 它是一个Vue.js官方提供的路由管理器。是一个功能更加强大的前端路由器,推荐使用。
- Vue Router和Vue.js非常契合,可以一起方便的实现SPA(single page web
application,单页应用程序)应用程序的开发。 - Vue Router依赖于Vue,所以需要先引入Vue,再引入Vue Router
Vue Router的功能特性:
- 支持H5历史模式或者hash模式
- 支持嵌套路由
- 支持路由参数
- 支持编程式路由
- 支持命名路由
- 支持路由导航守卫
- 支持路由过渡动画特效
- 支持路由懒加载
- 支持路由滚动行为
2. vue-router的基本使用
2.1Vue Router的使用步骤(★★★)
- 引入相关的库文件
- 添加路由链接
- 添加路由填充位
- 定义路由组件
- 配置路由规则并创建路由实例
- 把路由挂载到 Vue 根实例中
1. 引入相关的库文件
<!-- 导入 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>
2. 添加路由链接
<!-- router-link 是 vue 中提供的标签,默认会被渲染为 a 标签 -->
<!-- to 属性默认会被渲染为 href 属性 -->
<!-- to 属性的值默认会被渲染为 # 开头的 hash 地址 -->
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
3. 添加路由填充位
<!-- 路由填充位(也叫做路由占位符) -->
<!-- 将来通过路由规则匹配到的组件,将会被渲染到 router-view 所在的位置 -->
<router-view></router-view>
4. 定义路由组件
var User = {
template: '<div>User</div>'
}
var Register = {
template: '<div>Register</div>'
}
5. 配置路由规则并创建路由实例
// 创建路由实例对象
var router = new VueRouter({
// routes 是路由规则数组
routes: [
// 每个路由规则都是一个配置对象,其中至少包含 path 和 component 两个属性:
// path 表示当前路由规则匹配的 hash 地址
// component 表示当前路由规则对应要展示的组件
{path:'/user',component: User},
{path:'/register',component: Register}
]
})
6. 把路由挂载到 Vue 根实例中
new Vue({
el: '#app',
// 为了能够让路由规则生效,必须把路由对象挂载到 vue 实例对象上
router
});
2.2 路由重定向
- 路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面;
- 通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向:
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//path设置为/表示页面最初始的地址 / ,redirect表示要被重定向的新地址,设置为一个路由即可
{ path:"/",redirect:"/user"},
{ path: "/user", component: User },
{ path: "/login", component: Login }
]
})
3.1 嵌套路由用法
1. 嵌套路由功能分析(★★★)
- 点击父级路由链接显示模板内容
- 模板内容中又有子级路由链接
- 点击子级路由链接显示子级模板内容
2. 父路由组件模板
- 父级路由链接
- 父组件路由填充位
3. 子级路由模板
-
子级路由链接
-
子级路由填充位
4. 嵌套路由配置
父级路由通过children
属性配置子级路由
4. vue-router动态路由匹配
4.1 动态匹配路由的基本用法(★★★)
应用场景:通过动态路由参数的模式进行路由匹配
4.2 路由组件传递参数
$route与对应路由形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦
1. props的值为布尔类型
2. props的值为对象类型
3. props的值为函数类型
5. vue-router命名路由
5.1 命名路由的配置规则
- 为了更加方便的表示路由的路径,可以给路由规则起一个别名,即为“命名路由”。
6. vue-router编程式导航
6.1 页面导航的两种方式
声明式导航
:通过点击链接
实现导航的方式,叫做声明式导航 例如:普通网页中的<a></a>
链接 或 vue 中的<router-link></router-link>
编程式导航
:通过调用JavaScript
形式的API实现导航的方式,叫做编程式导航 例如:普通网页中的 location.href
6.2 编程式导航基本用法(★★★)
常用的编程式导航 API 如下:
- this.$router.
push
(‘hash地址’) - this.$router.
go
(n)
const User = {
template: '<div><button @click="goRegister">跳转到注册页面</button></div>',
methods: {
goRegister: function(){
// 用编程的方式控制路由跳转
this.$router.push('/register');
}
}
}
6.2 编程式导航参数规则
Vue-Router中常见的导航方式:
// 字符串(路径名称)
this.$router.push("hash地址");
this.$router.push("/login");
// 命名的路由(传递参数
this.$router.push({ name:'user' , params: {id:123} });
// 对象
this.$router.push({ path:"/login" });
// 带查询参数,变成 /register?uname=lisi
this. router.push({ path: '/register', query: { uname: 'lisi' }});
this.$router.go( n );//n为数字,参考history.go
this.$router.go( -1 );
7.实现后台管理案例(★★★)
案例效果:
用到的路由技术要点:
- 路由的基础用法
- 嵌套路由
- 路由重定向
- 路由传参
- 编程式导航
根据项目的整体布局划分好组件结构,通过路由导航控制组件的显示
案例思路:
- 抽离并渲染 App 根组件
- 将左侧菜单改造为路由链接
- 创建左侧菜单对应的路由组件
- 在右侧主体区域添加路由占位符
- 添加子路由规则
- 通过路由重定向默认渲染用户组件
- 渲染用户列表数据
- 编程式导航跳转到用户详情页
- 实现后退功能
- 点击左侧的"用户管理",“权限管理”,“商品管理”,“订单管理”,"系统设置"都会出现对应的组件并展示内容
- 其中"用户管理"组件展示的效果如上图所示,在用户管理区域中的详情链接也是可以点击的,点击之后将会显示用户详情信息。
//只需要把原本页面中的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>`
}
- .当我们访问页面的时候,默认需要展示刚刚创建的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>
- 此时我们打开页面应该就可以得到一个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
})
5.展示用户信息列表:
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>`}
6.当用户列表展示完毕之后,我们可以点击列表中的详情来显示用户详情信息,首先我们需要创建一个组件,用来展示详情信息
const UserInfo = {
props:["id"],
template:`<div>
<h5>用户详情</h5>
<p>查看 {{id}} 号用户信息</p>
<button @click="goBack">返回用户详情页</button>
</div> `,
methods:{
goBack(){
//当用户点击按钮,后退一页
this.$router.go(-1);
}
}
}
7.然后我们需要设置这个组件的路由规则
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
})
8.再接着给用户列表中的详情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);
}
}
}