实现路由的原因
(1)传统开发方式:url改变后,立刻发生请求响应整个页面,有可能资源过多,出现白屏的情况
(2)SPA(单页面应用Single Page Application)
锚点值发生改变后,不会立刻发送请求,而是在某个合适的时机,发送ajax请求,页面局部渲染
优点:页面不立刻跳转,用户体验好
前端路由的原理
<!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>
</head>
<body>
<a href="#/login">登录</a>
<a href="#/register">注册</a>
<div id="app"></div>
<script>
var oDiv = document.getElementById('app');
//当页面哈希值改变时触发
window.onhashchange = function () {
console.log(location.hash);
switch (location.hash) {
case '#/login':
oDiv.innerHTML= '我是登录页面'
break;
case '#/register':
oDiv.innerHTML= '我是注册页面'
break;
default:
break;
}
}
</script>
</body>
</html>
vue-router 的基本使用
- 安装
npm init --yes
npm install vue-router -S
vue-router是基于vue来使用的,所以使用vue-router的时候需要先引入vue.js,在引入vue-router.js
vue-router会返回一个VueRouter对象
使用vue-router需要实例化VueRouter对象,并且进行配置
实例化vue-router对象 var router = new VueRouter({});
VueRouter对象有一个属性
routes,该属性里是一个数组,我们需要在-
routes数组中放的是对象,对象有两个属性
path,component- path:存放的是组件的url,通过url找到对应的组件
- component:这里存放的是url对应的组件
注意:component的书写,是没有带s,带了s不会报错,也没有提示、 实例化
vue-rouer后需要将router对象挂载到Vue中-
在组件中使用
vue-router挂载router后会抛出全局组件
router-link、router-view- router-link 对应的是a标签
- router-view对应的是路由匹配的出口(有点类似于插槽的作用)
- router-link组件有一个属性
to,对应的是a标签的href属性
通过router-link来路由到对应的组件,然后将组件渲染到router-view中
<!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>
</head>
<body>
<div id="app"></div>
<!-- 1vue-router是基于vue的,所以在引入vue-router之前先引入vue -->
<script src="vue.js"></script>
<!-- 2引入vue-router -->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 定义两个组件
var Login ={
template:`
<div>
我是登录组件
</div>
`
};
var Register ={
template:`
<div>
我是注册组件
</div>
`
};
// 3 让vue来使用vue-router
// Vue.use('VueRouter') 全局下,不需要这句
// 3实例化vue-router对象,并且设置相应的属性
// vue-router对象里有一个属性routes,是一个数组,数组里面放的是每一个router组件的属性(path,component)
// path代表的是组件的路由,component代表是的组件
var router = new VueRouter({
routes:[
{
path:'/login',
component:Login
},
{
path:'/register',
component:Register
}
]
})
// 5 使用vue-router组件
// 使用vue-router的规则
// 引入vue-router 模块后抛出两个全局组件 router-link==>a to==>href router-view===>路由匹配组件的出口
var App = {
template:`
<div>
<router-link to='/login'>登录</router-link>
<router-link to='/register'>注册</router-link>
<router-view></router-view>
</div>
`,
}
new Vue({
el:'#app',
components:{
App
},
router,//4将router对象挂载到到vue中供使用
template:`<App/>`
})
</script>
</body>
</html>
效果:

命名路由
给路由对象添加一个属性name
修改的关键代码:
var router = new VueRouter({
routes:[
{
path:'/login',
name:'login',//添加name属性,为路由添加名字
component:Login
},
{
path:'/register',
name:'register',
component:Register
}
]
});
var App = {
// 这里使用:to="{name:'路由名字'}"的方式
template:`
<div>
<router-link :to='{name:"login"}'>登录</router-link>
<router-link :to='{name:"register"}'>注册</router-link>
<router-view></router-view>
</div>
`,
}
效果一样
路由参数
地址栏上的路由范式
-
xxxx.html#/user/1 params动态路由参数
动态路由参数,以冒号开头
oooo.html#/user?userId=1 query查询字符串方式
<!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>
</head>
<body>
<div id="app"></div>
<script src="vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
var userParams ={
template:`
<div>
我是用户1组件Params
</div>
`
};
var userQuery ={
template:`
<div>
我是用户2组件Query
</div>
`
};
var router = new VueRouter({
routes:[
{
path:'/user/:id',//动态路由参数,以冒号开头
name:'userP',
component:userParams
},
{
path:'/user',
name:'userQ',
component:userQuery
}
]
})
var App = {
template:`
<div>
<router-link :to='{name:"userP",params:{id:1}}'>用户1</router-link>
<router-link :to='{name:"userQ",query:{id:2}}'>用户2</router-link>
<router-view></router-view>
</div>
`,
}
new Vue({
el:'#app',
components:{
App
},
router,
template:`<App/>`
})
</script>
</body>
</html>
params的路有参数会将路由变成:动态路由参数.html#/user/1
query的路有参数会将路由变成:动态路由参数.html#/user?id=2
嵌套路由
在vue-router对象里的routes属性中的某个对象中,设置children属性,就说明当前组件又嵌套的子组件
routes:[
{
path:'/home',//动态路由参数,以冒号开头
name:'home',
component:Home,
children:[
{
path:'song',
component:Song
},
{
path:'movie',
component:Movie
}
]
}
]
例子:
<!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>
</head>
<body>
<div id="app"></div>
<script src="vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
var Home ={
template:`
<div>
<p>我是首页信信息</p>
<router-link to='/home/song'>歌曲</router-link>
<router-link to='/home/movie'>电影</router-link>
<router-view></router-view>
</div>
`
};
var Song ={
template:`
<div>
我是歌曲信息
</div>
`
};
var Movie ={
template:`
<div>
我是电影信息
</div>
`
};
var router = new VueRouter({
routes:[
{
path:'/home',//动态路由参数,以冒号开头
name:'home',
component:Home,
children:[
{
path:'song',
component:Song
},
{
path:'movie',
component:Movie
}
]
}
]
})
var App = {
template:`
<div>
<router-link :to='{name:"home"}'>首页</router-link>
<router-view></router-view>
</div>
`,
}
new Vue({
el:'#app',
components:{
App
},
router,
template:`<App/>`
})
</script>
</body>
</html>
动态路由匹配
响应路有参数的变化:当使用路由参数的时候,例如从/timeline/fronted导航到/timeline/backend,原来的组件实例会被复用。因为两个路由都渲染同一个组件,比起销毁再创建,复用则显得更加高效。不过这也意味着组件的声明周期钩子不会再被调用。
使用watch 在组件的内部监听路由信息的变化
watch:{
'$route'(to, from){
//to 表示要前往的路由组件
//from 表示从哪里来的路由组件
}
}
例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 使用watch 来监测路由的变化 来改变请求
var comDesc ={
data(){
return {
msg:''
}
},
template:`
<div>
我是{{msg}}
</div>
`,
created(){
this.msg = 'fronted';
},
watch:{
'$route'(to,from){
console.log(to);
console.log(from);
this.msg = to.params.id;
}
}
}
var TimeLine = {
template:`
<div>
<router-link :to="{name:'comDesc',params:{id:'fronted'}}">前端</router-link>
<router-link :to="{name:'comDesc',params:{id:'backend'}}">后端</router-link>
<router-view></router-view>
</div>
`
}
var Pins = {
template:`
<div>
我是沸点
</div>
`
}
var router = new VueRouter({
routes:[
{
path:'/timeline',
component:TimeLine,
children:[
{
name:'comDesc',
path:'/timeline/:id',//动态路由参数
component:comDesc
}
]
},
{
path:'/pins',
component:Pins,
}
]
});
var App = {
template:`
<div>
<router-link to="/timeline">首页</router-link>
<router-link to="/pins">沸点</router-link>
<router-view></router-view>
</div>
`
}
new Vue({
el:'#app',
components:{
App
},
router,
template:`<App/>`
})
</script>
</body>
</html>
keep-alive在路由中的使用
使用keep-alive在路由中将组件的状态缓存起来,例如,在一个页面中进行点击操作之后改变的页面的数据或者状态颜色等等,然后跳转到其他子组件中,再返回的时候,如果不使用keep-alive,则页面将被销毁并且重新加载渲染,使用keep-alive页面将被缓存起来。这样使用也可以减少页面性能消耗,主要根据不同业务场景来使用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
var TimeLine = {
template:`
<div>
我是首页
</div>
`,
created(){
console.log('首页组件被创建');
},
mounted(){
console.log('首页组件被渲染');
},
destroyed(){
console.log('首页组件被销毁');
}
}
var Pins = {
template:`
<div>
<h3 @click="changeColor">我是沸点</h3>
</div>
`,
methods:{
changeColor(e){
console.log(e);
e.target.style.color = 'red';
}
},
created(){
console.log('沸点组件被创建');
},
mounted(){
console.log('沸点组件被渲染');
},
destroyed(){
console.log('沸点组件被销毁');
}
}
var router = new VueRouter({
routes:[
{
path:'/timeline',
component:TimeLine,
},
{
path:'/pins',
component:Pins,
}
]
});
var App = {
// 使用keep-alive组件将视图组件包裹起来,来避免组件被频繁的销毁创建,也可以保留组件的状态
template:`
<div>
<router-link to="/timeline">首页</router-link>
<router-link to="/pins">沸点</router-link>
<!--<router-view></router-view>-->
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
`
}
new Vue({
el:'#app',
components:{
App
},
router,
template:`<App/>`
})
</script>
</body>
</html>


从例子我们可以看到,路由改变时,路由对应的组件将会被创建,之前的组件会被销毁,所以之前组件所操作所执行的状态将会被销毁,无法保留,但是使用keep-alive就能使组件的状态被保存。
meta的使用--权限控制
1、首先使用meta对子组件的routes进行配置,meta属性为对象
routes:[
{
path:'/blog',
comppnent:Blog,
meta:{
auth:true
}
}
]
2、在使用router.beforeEach((to, from, next) => {}) 对子组件进行路前置守卫;
router.beforeEach((to, from, next) => {
// ...
//to 为到那个组件中去
//from 为从哪个组件来
//这里可以从to.meta.auth中知道是为true还是false 如果是true则说明访问的子组件需要被验证。
next();//next() 则为放行
})
next(): 里面可以传值{path:'/login'}
例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/blog">我的博客</router-link>
<a href="javascript:void(0)">退出</a>
<router-view></router-view>
</div>
<script src="vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
Vue.use(VueRouter);
var Home = {
template: `
<div>
我是首页
</div>
`
}
var Blog = {
template: `
<div>
我的博客
</div>
`
}
var Login = {
data(){
return {
name:'',
pwd:'',
}
},
template: `
<div>
<input type="text" v-model='name' />
<input type="password" v-model='pwd' />
<input type="button" value='登录' @click="loginHandler" />
</div>
`,
methods:{
loginHandler(){
localStorage.setItem('user',{'name':this.name,'pwd':this.pwd});
// 使用路由跳转到博客页面
this.$router.push({
name:'blog'
})
}
}
}
var router = new VueRouter({
routes: [
{
path: '/',
redirect: '/home'
// 重定向到home
},
{
path: '/home',
component: Home,
},
{
path: '/blog',
component: Blog,
name:'blog',
// meta 是给路由做权限控制 如果auth:true 则说明访问该组件的时候需要登录
// 需要结合路由的检测
meta: {
auth: true
}
},
{
path:'/login',
component:Login
}
]
});
// 你可以使用 router.beforeEach 注册一个全局前置守卫: --官网
router.beforeEach((to, from, next) => {
if(to.meta.auth){
//如果meta的auth为true 则需要验证该路由 需要登录后才能操作
if(localStorage.getItem('user')){
//如果用户已经登录过了,就直接放行。
next();
}else{
next({
path:'/login'
})
}
}
next();
})
new Vue({
el: '#app',
router,
})
</script>
</body>
</html>
this.$router.push({'name':'/blog'})
使用全局$router来进入到组件内
