一,基本概念与原理
也就是说,后端路由就是之前学习的写服务器端的代码:
//post请求参数的获取
app.post('/add',(req,res)=>{
//接收post请求参数,
res.send(req.body)
})
//get请求参数的获取
app.get('/index',(req,res)=>{
res.send(req.query)
})
也就是说后端渲染存在性能问题,只能支持页面全局渲染更新,于是引出了ajax技术,可以实现局部更新,但是ajax又实现不了历史记录的前进后退,于是引入了spa单页面技术,页面的局部渲染利用ajax进行,历史记录的前进后退利用url的哈希不同来访问!
于是引出了前端路由的概念:
二,实现一个简单的前端路由
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" type="text/css" href="css/base.css"/>
<style type="text/css">
#app{
width: 20%;
margin: 200px auto;
border: 1px solid #ccc;
line-height: 30px;
padding: 20px;
}
</style>
</head>
<body>
<div id="app">
<a href="#/zhuye" >主页</a>
<a href="#/keji" >科技</a>
<a href="#/caijing">财经</a>
<a href="#/yule" >娱乐</a>
<!-- 根据:is属性指定的组件名称,把对应的组件渲染到component标签所在的位置。 -->
<component v-bind:is="comName"></component>
</div>
<!-- <script type="text/javascript" src="js/axios.js"></script> -->
<script type="text/javascript" src="js/vue.min.js"></script>
<script>
// 定义需要的四个组件
const zhuye={
template:'<h1>主页信息</h1>'
}
const keji={
template:'<h1>科技信息</h1>'
}
const caijing={
template:'<h1>财经信息</h1>'
}
const yule={
template:'<h1>娱乐信息</h1>'
}
//将这四个组件祖册为vm的私有组件
var vm= new Vue({
el:'#app',
data:{
comName:'zhuye'
},
components:{
zhuye,
keji,
caijing,
yule
}
})
//监听window的onhashchange事件,根据获取到的最新的hash值,切换要显示的组件的名称
window.onhashchange=function(){
//通过location.hash获取到最新的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-router简单介绍
它是 vue官方的路由管理器
四,vue-router的基本使用
需要注意的是,这里得按照顺序引入!
<script type="text/javascript" src="js/vue.min.js"></script>
<script type="text/javascript" src="js/vue-router_3.0.2.js"></script>
<div id="app">
<router-link to="/user">user</router-link>
<!-- 自动转化为a标签,to后是哈希值 -->
<router-link to="/register">register</router-link>
</div>
<!-- 路由占位符 -->
<router-view></router-view>
const user={
template:'<h1>user 组件</h1>'
}
const register={
template:'<h1>register 组件</h1>'
}
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/user',component:user},
{path:'/register',component:register},
//匹配的哈希值,展示的对应组件名
]
})
var vm= new Vue({
el:'#app',
data:{},
//挂载路由实例对象
router
})
于是这个基础的router路由就创建完成:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript" src="js/vue.min.js"></script>
<script type="text/javascript" src="js/vue-router_3.0.2.js"></script>
</head>
<body>
<div id="app">
<router-link to="/user">user</router-link>
<!-- 自动转化为a标签,to后是哈希值 -->
<router-link to="/register">register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
<script type="text/javascript">
const user={
template:'<h1>user 组件</h1>'
}
const register={
template:'<h1>register 组件</h1>'
}
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/user',component:user},
{path:'/register',component:register},
//匹配的哈希值,展示的对应组件名
]
})
var vm= new Vue({
el:'#app',
data:{},
//挂载路由实例对象
router
})
</script>
</body>
</html>
实现的效果:
结合之前的理解,spa根据哈希值不同局部刷新内容,于是提供了两个不同的组件(多个组件),放置在页面的同一结构位置上(一个占位符)。而路由管理器的含义就体现在,把某个哈希值需要对应展示哪个组件统一放置在一个对象中管理了:
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/user',component:user},
{path:'/register',component:register},
//两个参数:匹配的哈希值,展示的对应组件名
]
})
五,路由重定向
上述的代码,当我们刚进入那个页面的时候,两者都不会显示,因为a链接还没有被点击,哈希值还不是指定的哈希值:
这时候就可以利用重定向!
也是在路由规则中写的:
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/',redirect:'/user'},
{path:'/user',component:user},
{path:'/register',component:register},
//匹配的哈希值,展示的对应组件名
]
})
六,嵌套路由
这就需要在register组件内的模板字符串中写tab1和tab2标签:
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>
`
}
接着需要定义路由规则:
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/',redirect:'/user'},
{path:'/user',component:user},
{
path:'/register',
component:register,
children:[
{path:'/register/tab1',component:tab1},
{path:'/register/tab2',component:tab2},
]
},
//匹配的哈希值,展示的对应组件名
]
})
于是整体的代码变成:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript" src="js/vue.min.js"></script>
<script type="text/javascript" src="js/vue-router_3.0.2.js"></script>
</head>
<body>
<div id="app">
<router-link to="/user">user</router-link>
<!-- 自动转化为a标签,to后是哈希值 -->
<router-link to="/register">register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
<script type="text/javascript">
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:`<h1>tab1 组件</h1>`
}
const tab2={
template:`<h1>tab2 组件</h1>`
}
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/',redirect:'/user'},
{path:'/user',component:user},
{
path:'/register',
component:register,
children:[
{path:'/register/tab1',component:tab1},
{path:'/register/tab2',component:tab2},
]
},
//匹配的哈希值,展示的对应组件名
]
})
var vm= new Vue({
el:'#app',
data:{},
//挂载路由实例对象
router
})
</script>
</body>
</html>
实际的效果:
七,动态路由匹配
那如果这样的路由成百上千个呢?这样写也太丑了!!
注意到,上述的路由,哈希只是末尾不同,但是他们对应的组件却是相同的,那么可不可以用一个变量来代替变化的哈希呢?
于是就引入了动态路由匹配:
<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>
<!-- 自动转化为a标签,to后是哈希值 -->
<router-link to="/register">register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/',redirect:'/register'},
{path:'/user/:id',component:user},//:id就是告诉它,这后面的是个变量,无论是谁,都显示user组件
{path:'/register',component:register},
]
})
:id就是告诉它,这后面的是个变量,无论是谁,都显示user组件
这就能实现啦,但是还有问题,谁没事一样的页面结构,就哈希值不同???那就让它知道是哪个哈希。
通过$route.parame.id就能知道此时点击的哈希(就是那个:id变量的值)
const user={
template:`<h1>user {{$route.params.id}}组件</h1>`
}
于是:
八,路由组件传参
在第七条中,就出现了路由传参的用法:
r
o
u
t
e
.
p
a
r
a
m
s
但
是
route.params 但是
route.params但是route与对应路由形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦。
也就是说,props:true之后,就可以在组件中用props接收url中的"哈希变量",从而直接在模板字符串中使用了!!
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/',redirect:'/register'},
{path:'/user/:id',component:user,props:true},//这里设置了
{path:'/register',component:register},
]
})
对应的组件:
const user={
props:['id'],//就导致这里可以直接接收这个变量了
template:`<h1>user {{id}}组件</h1>`
}
学到这里,就会产生一个疑惑?它只能接收url中哈希值的"哈希变量"?那也太丑了?如果参数很多,难道url要写很长????那就更丑了!
于是就引入了props的值为对象类型:
但是这样写,id就接收不到了,为了同时可以接收这些参数和id信息,于是又引入了:
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/',redirect:'/register'},
{path:'/user/:id',component:user,
props:route=>({
name:'zhangsan',
age:12,
id:route.params.id //id本来就存在这里
})
},//这里设置了
{path:'/register',component:register},
]
})
const user={
props:['name','age','id'],//就导致这里可以直接接收这个变量了
template:`<h1>user的名字是:{{name}},年龄是:{{age}},id的值是{{id}}</h1>`
}
九,命名路由
就是给指定的路由起一个名字,需要使用时,只需要知道对应路由的名字可以使用了:
<router-link :to="{name:'user'}">user1</router-link>
<!-- 因为命名了,就可以直接使用名字啦 -->
<!-- 需要注意的是这里是绑定:to -->
//配置路由规则并创建路由实例
var router =new VueRouter({
//所有的路由规则
routes:[
{path:'/',redirect:'/register'},
{
path:'/user/:id',component:user,
name:'user' //给这个路由命名了
},
{path:'/register',component:register},
]
})
十,编程式导航
const user={
props:['id'],//就导致这里可以直接接收这个变量了
template:`
<div>
<h1>user</h1>
<button @click='gorester'>跳转到注册页面</button>
</div>
`,
methods:{
gorester:function(){
//使用函数式编程控制路由跳转
this.$router.push('/register')
}
}
}
再利用$router.go()后退回去:
const register={
template:`<div>
<h1>register 组件</h1>
<button @click='goback'>后退</button>
</div>
`,
methods:{
goback:function(){
//使用函数式编程控制路由跳转
this.$router.go(-1)
}
}
}
实现的效果: