在开发中,路由分为后端路由和前端路由。
后端路由,根据不同的用户URL请求,返回不同的内容,后端路由的本质就是URL请求地址与服务器资源之间的对应关系。后端路由根据不同的URL地址分发不同的资源。
前端路由,根据不同的用户事件,显示不同的页面内容。本质就是用户事件与事件处理函数之间的对应关系。前端路由负责事件监听,触发事件之后,通过事件函数渲染不同内容。
ajax前端渲染,前端渲染提供性能,但是不支持浏览器的前进后退操作
SPA——单页面应用,不仅页面交互无刷新,甚至页面跳转也可以无刷新,前端路由随之应运而生。SPA实现原理之一就是基于URL地址的hash,hash的变化会导致浏览器记录访问历史的变化,但是hash的变化不会触发新的URL请求。在实现SPA过程中,最核心的技术点就是前端路由。
一.路由的基本概念与原理,实现简易前端路由。
基于URL的hash实现,点击菜单的时候改变url的hash,根据hash的变化控制组件的切换。
window.onhashchange,监听window的onhashchange事件,获取最新的hash值,切换要显示组建的名称,通过location.hash获取到最新的hash值。
<!-- 被Vue实例控制的div区域 -->
<div id="app">
<div v-text="name"></div>
<!-- 切换组件的超链接 -->
<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 type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/* 创建需要被切换的四个组件 */
var zhuye = {
template: '<h1>主页信息</h1>',
};
var keji = {
template: '<h1>科技信息</h1>',
};
var caijing = {
template: '<h1>财经信息</h1>',
};
var yule = {
template: '<h1>娱乐信息</h1>',
};
/* 创建Vue的实例对象 */
var vm = new Vue({
el: '#app',
data: {
name: 'hello world!!!',
comName: 'zhuye',
},
components: {
zhuye,
keji,
caijing,
yule,
},
});
window.onhashchange = function() {
// 通过location.hash获取到最新的hash值.
console.log(location.hash, location.hash.slice(1));
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>
二.Vue路由管理器。
1.基本使用:
使用步骤:
1.引入相关的库文件。 2.添加路由链接。 3.添加路由填充位。 4.定义路由组件。 5.配置路由规则并创建路由实例。 6.把路由挂载到vue和实例中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<!-- 第一步,导入vue文件,为全局window对象挂载vue构造函数 -->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- 导入vue-router文件,为全局window对象挂载vueRouter构造函数 -->
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<!-- 第二步,添加路由链接。 -->
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
<!-- 第三步,添加路由填充为 -->
<router-view></router-view> //路由组件中template的东西会会被动态加载到这里
</div>
<script type="text/javascript">
/* 第四步,定义路由组件 */
var User = {
template: ...,
};
var Register = {
template: ...,
};
/* 第五步,配置路由规则并创建路由实例。 */
// 创建路由实例对象
var router = new VueRouter({
// routes是路由规则数组
routes: [
// 每个路由规则都是一个配置对象,其中至少包含path和component两个属性
{
path: '/user', // path表示当前路由规则匹配的hash地址
component: User, // component表示当前路由规则对应要展示的组件组件名
// 称,不是字符串
},
{
path: '/register',
component: Register,
}
]
});
// 创建vm实例对象
var vm = new Vue({
el: '#app',
data: {
},
// 第六步,把路由挂载到Vue根实例中
// 为了能够让路由规则生效,必须把路由对象挂载到Vue实例对象上
router: router,
});
</script>
</body>
</html>
2.路由重定向
路由重定向指的是,用户在访问地址A的时候,强制用户跳转到地址C,从而展示特定的组件页面
通过路由规则的redirect属性,指定一个新的路由地址,可以很方便的设置路由的重定向
大部分代码与第一小点的一致,只需要在路由实例对象中routes(路由规则数组)中加入以下代码
{
path:'/', //表示需要被重定向的原地址
redirect:'/user' //redirect表示将要被重定向道德新地址
}
3.Vue router嵌套路由
first:首先创建父路由组件模板,父级路由链接,父组件路由填充位。 second:然后创建子级路由模板,子级路由连接填充位。 third:然后配置嵌套路由配置,父级路由通过children属性配置子级路由。
大部分代码与第一小点的一致,只需要将第1小点的定义路由组件改为下面代码:
var User = {
template: '<h1>User</h1>',
};
var 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>
`,
<router-view></router-view> //子级路由填充位置
};
var Tab1 = {
template: '<h1>Tab1</h1>',
};
var Tab2 = {
template: '<h1>Tab2</h1>',
};
ps:在父级路由组件中,将在父级路由组件外面定义的子级路由组件写入。
再在以上的基础上,在路由实例对象中routes(路由规则数组)中实现了子级路由的父级路由中加入以下代码(在上面的例子中,是在父级路由组件Register中加入了子级路由组件):
{
path: '/register',
component: Register,
// 通过children属性,为/register添加子路由规则
children: [{
path: '/register/tab1',
component: Tab1
},
{
path: '/register/tab2',
component: Tab2
},
]
},
4.Vue Router动态路由匹配
动态路由匹配,指的是如果某些路由规则一部分是完全一样的,只有另外一部分是动态变化的,这些动态变化的部分形成路由参数,这些路由参数就叫做动态路由匹配。
动态路由参数,以冒号开头,冒号后面的名字就是匹配的名称,通过动态路由参数的模式进行路由匹配。路由组件中通过$route.params获取路由参数。
<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="/user/4">User4</router-link>
<router-view></router-view>
</div>
var User = {
template: '<h1>User组件,用户id为: {{$route.params.id}}</h1>',
};
var router = new VueRouter({
// routes是路由规则数组
routes: [
{
path: '/user/:id',
component: User,
},
{
path: '/',
redirect: '/user'
}
]
});
5.Vue Router路由组件传递参数
$route与对应路由会形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦。
props的值为布尔类型。如果将props值设置为true,route.params将会被设置为组件属性。
使用props接受路由参数,直接使用参数名称来使用路由参数。
在第4小点的代码基础上定义路由组件的位置改为以下代码:
var User = {
//使用props接收路由参数
props: ['id'],
// 使用路由参数.
template: '<h1>User组件,用户id为: {{id}}</h1>',
};
再在路由实例对象的路由规则数组routes中,将User组件配置加上props属性,并且将其值设置为true,如以下代码:
{
path: '/user/:id', // 动态路由匹配
component: User, // 组件名称,不是字符串
//如果props被设置为true。route.params将会被设置为组件属性。
props: true,
},
ps:若props是一个对象,则它会被按照原样设置为组件属性,对象中有什么数据组件中就可以接受到什么数据。若props的值为函数类型,如果props是一个函数,则这个函数接受route对象为子级的形参。
与上面基本一致的代码,但是在定义的路由组件中定义的props是一个对象,代码如下:
var User = {
//使用props接收路由参数
props: ['id', 'uname', 'age'],
// 使用路由参数.
template: '<h1>User组件,用户为: {{id}} {{uname}} {{age}}</h1>',
};
再在路由实例对象的路由规则数组routes中, 配置组件User:
{
path: '/user/:id', // 动态路由匹配
component: User, // 组件名称,不是字符串
/* 如果props是一个对象,它会被按原样设置为组件属性。 */
/* props: {
uname: '张飒飒',
age: 12
}, */
/*如果props是一个函数, 则这个函数接收route对象为子级的形参
route对象就是路由中的动态参数对象,路径中有几个参数项,
route里面就有几个参数值.*/
// 返回一个props对象
props: route => ({
uname: '张飒飒',
age: 20,
id: route.params.id,
})
},
6.Vue Router编程式导航
前言:为了更加方便的表示路由的路径,可以给路由规则起一个别名,即为命名路由。通过命名路由可以实现页面的跳转,这样子就可以用在编程式导航中。
而页面导航分为两种:
第一种是声明式导航(通过点击链接实现导航的方式),例如普通网页中的<a>标签或者Vue中的<route-link>标签。
第二种就是编程式导航,通过调用js形式的API实现导航的方式,叫做编程式导航,例如普通网页中的location.href。 而Vue中常用的编程式导航为this。语法如下:
this.$router.push('hash地址')
this.$router.go('1或-1') //实现历史记录中的前进和后退,1是前进,2是后退
大部分代码相同,即将以下代码放入相应位置即可:
标签<body>中的<div>块(这里为命名路由):
<!-- 要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象: -->
<router-link :to="{name:'user',params:{id:123456}}">User3</router-link>
用以下代码替代定义了的路由组件User:
var User = {
props: ['id', 'uname', 'age'], //使用props接收路由参数
/* 编程式导航的使用 */
template: `
<div>
<h1>User组件,用户为: {{id}} {{uname}} {{age}}</h1>
<button @click="goRegister">跳转到注册页面</button>
</div>
`,
methods: {
goRegister: function() {
// 用编程式的方式控制路由跳转
this.$router.push('/register');
}
},
};
而用以下代码替代定义了的路由组件Register:
var 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>
<button @click="goBack">返回到上一步</button>
</div>
`,
methods: {
goBack: function() {
// 用编程式的方式控制路由跳转
this.$router.go('-1');
}
},
};
再在路由实例对象处的路由规则数组routes中,更改User路由组件的相关规则:
{
path: '/user/:id', // 动态路由匹配
component: User, // 组件名称,不是字符串
props: route => ({ // 返回一个props对象
uname: '张飒飒',
age: 20,
id: route.params.id,
}),
/* 命名路由 */
//上面的body标签中的div块的命名路由来自这里
name: 'user', // 通过路由的name属性可以实现导航和跳转功能
},