5:Vue前端路由
一:路由的概念路由的本质就是一种对应关系,比如说我们在url地址中输入我们要访问的url地址之后,浏览器要去请求这个url地址对应的资源。那么url地址和真实的资源之间就有一种对应的关系,就是路由。路由分为前端路由和后端路由1).后端路由是由服务器端进行实现,并完成资源的分发2).前端路由是依靠hash值(锚链接)的变化进行实现后端路由性能相对前端路由来说较低,所以,我们接下来主要学习...
一:路由的概念
路由的本质就是一种对应关系,比如说我们在url地址中输入我们要访问的url地址之后,浏览器要去请求这个url地址对应的资源。
那么url地址和真实的资源之间就有一种对应的关系,就是路由。
1. 路由分为前端路由和后端路由
1).后端路由
是由服务器端进行实现,并完成资源的分发
概念:根据不同的用户 URL 请求
,返回不同的内容
本质:URL 请求地址与服务器资源
之间的对应关系
图解:
2).前端路由
是依靠hash值(锚链接)的变化进行实现
概念:根据不同的用户事件
,显示不同的页面内容
本质:用户事件与事件处理函数
之间的对应关系
图解:
注意:前端路由主要做的事情就是监听事件并分发执行事件处理函数。
2. SPA(Single Page Application) 介绍
- 后端渲染(存在性能问题。后端路由性能相对前端路由来说较低)
- Ajax前端渲染(
前端渲染提高性能
,但是不支持浏览器的前进后退操作) SPA
(Single Page Application)单页面应用程序:整个网站只有一个页面
,内容的变化通过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);
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
}
}
三:Vue Router简介
它是一个Vue.js官方提供的路由管理器。是一个功能更加强大的前端路由器,推荐使用。
Vue Router和Vue.js非常契合,可以一起方便的实现SPA(single page web application,单页应用程序)应用程序的开发。
Vue Router依赖于Vue,所以需要先引入Vue,再引入Vue Router
Vue Router的特性:
- 支持H5历史模式或者hash模式
- 支持嵌套路由
- 支持路由参数
- 支持编程式路由
- 支持命名路由
- 支持路由导航守卫
- 支持路由过渡动画特效
- 支持路由懒加载
- 支持路由滚动行为
四:Vue Router的使用步骤(★★★)
1.导入js文件
<script src="lib/vue_2.5.22.js"></script>
<script src="lib/vue-router_3.0.2.js"></script>
2.添加路由链接:"router-link"是路由中提供的标签,默认会被渲染为a标签,to属性默认被渲染为href属性,to属性的值会被渲染为#开头的hash地址
<router-link to="/user">User</router-link>
<router-link to="/login">Login</router-link>
3.添加路由填充位(路由占位符)
<router-view></router-view>
4.定义路由组件
var User = { template:"<div>This is User</div>" }
var Login = { template:"<div>This is Login</div>" }
5.配置路由规则并创建路由实例
var myRouter = new VueRouter({
//routes是路由规则数组
routes:[
//每一个路由规则都是一个对象,对象中至少包含path和component两个属性
//path表示 路由匹配的hash地址,component表示路由规则对应要展示的组件对象
{path:"/user",component:User},
{path:"/login",component:Login}
]
})
6.将路由挂载到Vue实例中
new Vue({
el:"#app",
//通过router属性挂载路由对象
router:myRouter
})
小结:
Vue Router的使用步骤还是比较清晰的,按照步骤一步一步就能完成路由操作
1.导入js文件
2.添加路由链接
3.添加路由占位符(最后路由展示的组件就会在占位符的位置显示)
4.定义路由组件
5.配置路由规则并创建路由实例
6.将路由挂载到Vue实例中
补充:
路由重定向:可以通过路由重定向为页面设置默认展示的组件
在路由规则中添加一条路由规则即可,如下:
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//path设置为/表示页面最初始的地址 / ,redirect表示要被重定向的新地址,设置为一个路由即可
{ path:"/",redirect:"/user"},
{ path: "/user", component: User },
{ path: "/login", component: Login }
]
})
实例:
<!-- 被vue实例所控制的区域 -->
<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: '<h1>register组件</h1>'
};
// 创建路由实例对象
const router = new VueRouter({
// 所有路由规则
// 路由重定向至user(关键字redirect)
routes: [{
path: '/',
redirect: '/user'
}, {
path: '/user',
component: User
}, {
path: '/register',
component: Register
}]
});
// 创建vm实例
var vm = new Vue({
//指定控制区域
el: '#app',
data: {},
methods: {},
// 挂载路由
router
});
</script>
五:嵌套路由,动态路由的实现方式
1.嵌套路由的概念(★★★)
- 当我们进行路由的时候显示的组件中还有新的子级路由链接以及内容。
- 嵌套路由最关键的代码在于理解子级路由的概念:
比如我们有一个/register的路由
那么/login下面还可以添加子级路由,如:
/register/tab1
/register/tab2
参考代码如下:
<!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">
<script src="../vue.js"></script>
<script src="../vue-router.js"></script>
<title>Document</title>
</head>
<body>
<!-- 被vue实例所控制的区域 -->
<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></router-view>
</div>
`
};
//定义嵌套组件
const Tab1 = {
template: '<div>1</div>'
};
const Tab2 = {
template: '<div>2</div>'
};
// 创建路由实例对象
const router = new VueRouter({
// 所有路由规则
// 路由重定向至user(关键字redirect)
// children数组表示子路由规则
routes: [{
path: '/',
redirect: '/user'
}, {
path: '/user',
component: User
}, {
path: '/register',
component: Register,
children: [{
path: '/register/tab1',
component: Tab1
}, {
path: '/register/tab2',
component: Tab2
}]
}]
});
// 创建vm实例
var vm = new Vue({
//指定控制区域
el: '#app',
data: {},
methods: {},
// 挂载路由
router
});
</script>
</body>
</html>
页面效果大致如下:
2.动态路由匹配(★★★)
- 应用场景:通过动态路由参数的模式进行路由匹配
var User = { template:"<div>用户:{{$route.params.id}}</div>"}
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//通过/:参数名 的形式传递参数
{ path: "/user/:id", component: User },
]
})
实例(js代码引入省略):
<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-view></router-view>
</div>
<script>
const User = {
template: '<h1>User{{$route.params.id}}</h1>'
}
const router = new VueRouter({
routes: [{
path: '/',
component: User
}, {
path: '/user/:id',
component: User
}]
});
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
补充:
如果使用$route.params.id来获取路径传参的数据不够灵活。
1.我们可以通过props来接收参数(值为布尔类型)
var User = {
props:["id"],
template:"<div>用户:{{id}}</div>"
}
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//通过/:参数名 的形式传递参数
//如果props设置为true,route.params将会被设置为组件属性
{ path: "/user/:id", component: User,props:true },
]
})
实例:
<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-view></router-view>
</div>
<script>
const User = {
props: ['id'],
template: '<div>User{{id}}</div>'
};
const router = new VueRouter({
routes: [{
path: '/user/:id',
component: User,
props: true
}]
});
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
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} },
]
})
实例:
<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-view></router-view>
</div>
<script>
const User = {
props: ['name', 'age', 'id'],
template: `<div>姓名{{name}}+'-- -- '+年龄{{age}}+'-- --'+id{{id}}</div>`
}
const router = new VueRouter({
routes: [{
path: '/user/:id',
component: User,
props: {
name: 'lisi',
age: 18
}
}]
});
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
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}
}
},
]
})
实例:
<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-view></router-view>
</div>
<script>
const User = {
props: ['name', 'age', 'id'],
template: `<div>姓名{{name}}+'-- -- '+年龄{{age}}+'-- --'+id{{id}}</div>`
}
const router = new VueRouter({
routes: [{
path: '/user/:id',
component: User,
props: route => ({
name: 'lisi',
age: 18,
id: route.params.id
})
}]
});
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
六:命名路由以及编程式导航
1.命名路由:给路由取别名
案例:
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//通过name属性为路由添加一个别名
{ path: "/user/:id", component: User, name:"user"},
]
})
//添加了别名之后,可以使用别名进行跳转
<router-link to="/user">User</router-link>
<router-link :to="{ name:'user' , params: {id:123} }">User</router-link>
//还可以编程式导航
myRouter.push( { name:'user' , params: {id:123} } )
实例:
<div id="app">
<router-link :to="{name:'user',params:{id:1}}">user</router-link>
<router-view></router-view>
</div>
<script>
const User = {
props: ['name', 'age', 'id'],
template: `
<div>{{name}}---{{age}}---{{id}}</div>
`
}
const router = new VueRouter({
routes: [{
name: 'user',
path: '/user/:id',
component: User,
props: route => ({
name: 'lisi',
age: 12,
id: route.params.id
})
}]
});
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
2.编程式导航(★★★)
页面导航的两种方式:
- 1.声明式导航:通过点击链接的方式实现的导航
- 2.编程式导航:调用js的api方法实现导航
push()
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"} });
go()
this.$router.go( n );//n为数字,参考history.go
this.$router.go( -1 );
案例:
场景:从user跳转到register,再从register后退回来
<!-- 被vue实例所控制的区域 -->
<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: `
<div>
<h1>User组件</h1>
<button @click="goRegister">跳转至注册页面</button>
</div>
`,
methods: {
goRegister() {
this.$router.push('/register');
}
}
};
const Register = {
template: `
<div>
<h1>register组件</h1>
<button @click="goBack">返回</button>
</div>
`,
methods: {
goBack() {
this.$router.go(-1);
}
}
};
// 创建路由实例对象
const router = new VueRouter({
// 所有路由规则
// 路由重定向至user(关键字redirect)
routes: [{
path: '/',
redirect: '/user'
}, {
path: '/user',
component: User
}, {
path: '/register',
component: Register
}]
});
// 创建vm实例
var vm = new Vue({
//指定控制区域
el: '#app',
data: {},
methods: {},
// 挂载路由
router
});
</script>
last:案例
案例效果
点击左侧的"水果管理",“苹果管理”,“香蕉管理”,“橘子管理”,"西瓜设置"都会出现对应的组件并展示内容
其中"水果管理"组件展示的效果如上图所示,在用户管理区域中的详情链接也是可以点击的,点击之后将会显示用户详情信息,点击后退,回到上一次点击页面
案例思路
1).实现静态页面的展示
2).在页面中引入vue,vue-router
3).创建Vue实例对象,准备开始编写代码实现功能
4).希望是通过组件的形式展示页面的主体内容,而不是写死页面结构,所以我们可以定义一个根组件:
来逐个渲染其他组件
5).当我们访问页面的时候,默认需要展示刚刚创建的app根组件,我们可以创建一个路由对象来完成这个事情,然后将路由挂载到Vue实例对象中即可
6).此时我们打开页面应该就可以得到一个VueRouter路由出来的根组件了,我们需要在这个根组件中继续路由实现其他的功能子组件,先让我们更改根组件中的模板:更改左侧li为子级路由链接,并在右侧内容区域添加子级组件占位符,然后,我们要为子级路由创建并设置需要显示的子级组件
7).展示水果信息列表
8).当用户列表展示完毕之后,我们可以点击列表中的详情来显示用户详情信息,首先我们需要创建一个组件,用来展示详情信息;然后我们需要设置这个组件的路由规则
9).再接着给用户列表中的详情a连接添加事件;最后为详情页组件添加编程式导航(回退)
码代码(部分细节在注释)
<!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">
<script src="../vue.js"></script>
<script src="../vue-router.js"></script>
<title>Document</title>
<style>
html,
body,
#app {
margin: 0;
padding: 0px;
height: 100%;
}
.header {
height: 50px;
background-color: #32cd32;
line-height: 50px;
text-align: center;
font-size: 24px;
color: black;
}
.footer {
height: 40px;
line-height: 40px;
background-color: #32cd32;
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: #238e23;
}
.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: #215e21;
color: black;
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: #93db70;
}
</style>
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
<script>
//实现路由渲染根组件
const App = {
template: `
<div>
<!-- 头部区域 -->
<header class="header"><strong>原谅绿</strong>水果铺</header>
<!-- 中间主体区域 -->
<div class="main">
<!-- 左侧菜单栏 -->
<div class="content left">
<ul>
<li>
<router-link to="/fruits">水果管理</router-link>
</li>
<li>
<router-link to="/apples">苹果管理</router-link>
</li>
<li>
<router-link to="/banana">香蕉管理</router-link>
</li>
<li>
<router-link to="/orange">橘子管理</router-link>
</li>
<li>
<router-link to="/watermelon">西瓜管理</router-link>
</li>
</ul>
</div>
<!-- 右侧内容区域 -->
<div class="content right">
<div class="main-content">
<router-view></router-view>
</div>
</div>
</div>
<!-- 尾部区域 -->
<footer class="footer">版权信息</footer>
</div>
`
};
//创建左侧连接模板
const Fruits = {
data() {
return {
fruits: [{
id: 1,
name: '苹果',
produce: '中国'
}, {
id: 2,
name: '香蕉',
produce: '日本'
}, {
id: 3,
name: '橘子',
produce: '巴铁'
}, {
id: 4,
name: '西瓜',
produce: '印度'
}]
}
},
template: `
<div>
<h1>水果管理</h1>
<table>
<thead>
<tr>
<th>编号</th><th>姓名</th><th>产区</th><th>操作</th>
</tr>
</thead>
<tbody>
<tr :key="item.id" v-for="(item,index) in fruits">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.produce}}</td>
<td><a href="javascirpt:;" @click="goDetails(item.id)">详情</a></td>
</tr>
</tbody>
</table>
</div>
`,
methods: {
goDetails(id) {
//此处id前面要带'/'
this.$router.push('/details/' + id);
}
}
};
//创建详情页组件
const Details = {
props: ['id'],
template: `
<div>
<h1>欢迎来到详情页------水果id为:{{id}}</h1>
<button @click="goBack">后退</button>
</div>
`,
methods: {
goBack() {
//编程式导航,后退至上一步
this.$router.go(-1);
}
}
};
const Apples = {
template: `
<h1>苹果管理</h1>
`
};
const Banana = {
template: `
<h1>香蕉管理</h1>
`
};
const Orange = {
template: `
<h1>橘子管理</h1>
`
};
const Watermelon = {
template: `
<h1>西瓜管理</h1>
`
};
//创建路由规则
var router = new VueRouter({
routes: [{
path: '/',
component: App,
redirect: '/fruits',
// 路由位于根组件,是根组件的子路由
children: [{
path: '/fruits',
component: Fruits
}, {
path: '/apples',
component: Apples
}, {
path: '/banana',
component: Banana
}, {
path: '/orange',
component: Orange
}, {
path: '/watermelon',
component: Watermelon
}, {
path: '/details/:id',
component: Details,
// 携带id渲染
props: true
}]
}]
});
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
</body>
</html>
OVER
奥利给
更多推荐
所有评论(0)