上一篇Vue.js(三)主要学习了Vue组件的基本知识,这节主要是学习一下Vue路由
什么是路由?
- 后端路由:对于普通网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上的对应的资源
- 前端路由:对于单页面程序来说,主要通过URL中的hash(#)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容,所以,单页面程序的页面跳转主要用hash来实现。在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由)
在vue中使用vue-router
- 导包:
导入vue-router 组件类库,当导入包之后,在window全局对象中,就有了一个路由构造函数,叫做VueRouter
<script src="lib/vue-2.4.0.js"></script>
<script src="lib/vue-router-3.0.1.js"></script>
- 创建一个路由对象实例
先定义两个模板对象
routes:路由匹配规则,必有两个属性
+ path:监听 哪个路由地址
+ component:如果路由是前面匹配到的path,则表示component对应那个组件。component存放的是组件模板那对象
var router = new VueRouter({
routes: [
{ path: '/login', component: login },
{ path: '/register', component: register }
]
});
- 关联vue对象
用来监听URL的变化,然后展示对应组件
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router: routerObj
- 使用 router-view 组件来显示匹配到的组件
router-view相当于占位符
<router-view></router-view>
- 使用 router-link 组件来导航
router-link默认渲染成a标签,有点击触发事件,可以用tag属性设置
<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link>
- redirect重定向
由以上代码运行出来的页面,刚渲染出时,页面没有组件模块,只有router-link所显示的内容,只有点击之后,根据事件才有组件显示,这是因为页面进去是根路径,不是我们想要的登录组件,所以我们就需要定义进入页面是要显示的路径
以下是第一种办法,可以用,但是不推荐
{ path: '/', component: login},
这是第二种办法,借用redirect
var router = new VueRouter({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: login },
{ path: '/register', component: register }
]
});
- 设置选中路由高亮的方法
我们可以在Chrome控制台上看到,当选中的导航上有个router-link-active
class样式,我们可以修改他,来设置我们的样式
有两种方法:
+ router-link-active
重写router-link-active样式
+ linkActiveClass
定义一个样式名称,写样式
第一种:
.router-link-active{
color: red;
font-weight: 800;
font-style: italic;
font-size: 80px;
text-decoration: underline;
}
第二种:
var router = new VueRouter({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: login },
{ path: '/register', component: register }
],
linkActiveClass:'myActive'
});
.myactive {
color: red;
font-weight: 800;
font-style: italic;
font-size: 80px;
text-decoration: underline;
}
- 路由切换启动动画
用transition
包裹起来,再写上样式,注意加mode
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(140px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
</style>
<transition mode="out-in">
<router-view></router-view>
</transition>
路由规则中定义参数
两种方式:
- query
如果在路由中,使用查询字符串,给路由传递参数,则不需要修改路由规则的 path 属性
通过this.$route(在生命周期函数created中调用)可以获得路由相关的内容,例如,fullPath;我们可以发现,query中有我们传入的参数:
在模板中中,我们可以用$route.query.id
获得参数
<router-link to="/login?id=10&name=zs">登录</router-link>
<script>
var com1={
template: '<h1>登录模块----{{$route.query.id}}----{{$route.query.name}}</h1>',
created(){ // 组件的生命周期钩子函数
console.log(this.$route)
// console.log(this.$route.query.id)
}
};
</script>
- params
params需要修改path属性,内部实现路由正则表达式设置
<router-link to="/login/12/ls">登录</router-link>
<script>
var com1={
template: '<h1>登录模块----{{$route.params.id}}----{{$route.params.name}}</h1>',
created(){ // 组件的生命周期钩子函数
console.log(this.$route)
// console.log(this.$route.query.id)
}
};
var routerObj=new VueRouter({
routes:[
{path:'/login/:id/:name',component:com1},
{path:'/register',component:com2}
],
linkActiveClass:'myactive'
});
</script>
路由嵌套
实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件
应用场景:在选项卡中,顶部有数个导航栏,中间的主体显示的是内容;这个时候,整个页面是一个路由,然后点击选项卡切换不同的路由来展示不同的内容,这个时候就是路由中嵌套路由。
我们使用children属性实现路由嵌套
<div id="app">
<router-link to="/account">Account</router-link>
<router-view></router-view>
</div>
<template id="tmpl">
<div>
<h1>这是一个Account</h1>
<router-link to="/account/login">登录</router-link>
<router-link to="/account/register">注册</router-link>
<router-view></router-view>
</div>
</template>
<script>
var com1={
template: '<h1>登录模块</h1>'
};
var com2={
template: '<h1>注册模块</h1>'
};
var account={
template:'#tmpl'
};
var routerObj=new VueRouter({
routes:[
// {path:'/',redirect:'/account'},
{
path:'/account',
component:account,
children:[
{path:'login',component:com1},
{path:'register',component:com2}
]
},
],
linkActiveClass:'myactive'
});
var vm=new Vue({
el:'#app',
data:{},
methods:{},
router:routerObj
})
</script>
注意:1. 子路由path之前不加/
,否则永远一根路径开始请求,不方便理解URL地址 2. 在router-link中,路径要写全,写绝对路径
命名视图实现经典布局
通过vue实现上左右经典布局
- 首先,我们先写三个模板,分别是header、leftbox、mainbox;将这三个模板放在页面上(router-view)
- 我们需要思考的是:路由规则应该怎么写。我们在进入页面时,三个模板都存在,我们要实现的是,根路径情况下,显示三个模板。vue-router提供了
components
属性,区别于component,他可以匹配多个组件。components中提供了一个属性default
默认匹配。我们在components中定义视图名称:模板对象,通过在HTML标签中的属性name
来实现对应 - 设置各个模板的样式,采用flex布局
<style>
*{
margin: 0;
padding: 0;
}
h1{
margin: 0;
padding: 0;
}
.headbox{
background-color: lightgreen;
height: 80px;
}
.content{
display: flex;
height: 520px;
}
.leftbox{
background-color: lightblue;
flex: 2;
}
.mainbox{
background-color: lightgoldenrodyellow;
flex: 8;
}
</style>
<div id="app">
<router-view></router-view>
<div class="content">
<router-view name="left"></router-view>
<router-view name="main"></router-view>
</div>
</div>
<script>
var header={
template:'<h1 class="headbox">header</h1>'
};
var leftbox={
template:'<h1 class="leftbox">left</h1>'
};
var mainbox={
template:'<h1 class="mainbox">main</h1>'
};
var router=new VueRouter({
routes:[
{path:'/',components:{
'default':header,
'left':leftbox,
'main':mainbox
}}
]
});
var vm=new Vue({
el:'#app',
data:{},
router,
methods:{}
})
</script>
案例-名称案例
实现firstname+lastname=fullname
- 以methods中注册事件实现
绑定keyup事件
<div id="app">
<input type="text" v-model="firstname" @keyup="getFullName">+
<input type="text" v-model="lastname" @keyup="getFullName">=
<input type="text" v-model="fullname">
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
firstname:'',
lastname:'',
fullname:''
},
methods:{
getFullName(){
this.fullname=this.firstname+'-'+this.lastname;
}
}
})
</script>
- 使用watch属性实现
watch属性:可以监听data中指定数据的变化,然后触发watch中对应的处理函数
watch中的处理函数提供了两个参数:nValue、oValue
<div id="app">
<input type="text" v-model="firstname">+
<input type="text" v-model="lastname">=
<input type="text" v-model="fullname">
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
firstname:'',
lastname:'',
fullname:''
},
methods:{},
watch:{
firstname(nVaule){
this.fullname=nVaule+'-'+this.lastname;
},
'lastname'(nVaule){
this.fullname=this.firstname+'-'+nVaule;
}
}
})
</script>
- computed实现
computed:在computed中,可以定义一些属性,这些属性叫做计算属性,计算属性的本质就是一个方法,只不过,我们在使用计算属性的时候,是把他们的名称值直接当属性来使用,并不会当作方法来使用
<div id="app">
<input type="text" v-model="firstname">+
<input type="text" v-model="lastname">=
<input type="text" v-model="fullname">
<p>{{fullname}}</p>
<p>{{fullname}}</p>
<p>{{fullname}}</p>
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
firstname:'',
lastname:'',
},
methods:{},
computed:{
'fullname':function () {
console.log("ok");
return this.firstname+'-'+this.lastname
}
}
})
</script>
watch监听路由地址的改变
watch适合监听非DOM元素事件(虚拟的)
以下就是借助$route.path监听路由地址的改变
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(140px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
</style>
<body>
<div id="app">
<router-link to="/login" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>
<transition mode="out-in">
<router-view></router-view>
</transition>
</div>
</body>
<script>
var login = {
template: '<h1>登录组件</h1>'
};
var register = {
template: '<h1>注册组件</h1>'
};
var routerObj = new VueRouter({
routes: [
{ path: '/login', component: login },
{ path: '/register', component: register }
]
});
var vm=new Vue({
el:'#app',
data:{},
methods:{},
watch:{
'$route.path'(nValue){
if (nValue==='/login'){
console.log('欢迎来到登录页面')
} else if (nValue==='/register') {
console.log('欢迎来到注册页面');
}
}
},
router: routerObj
})
</script>
computed 3个注意点
- 计算属性在引用的时候,一定不加
()
,直接把它当作属性使用 - 只要计算属性function内部所用到的任何data数据发生了变化,就会立即重新计算这个计算属性的值
- 计算属性的求值结果,会被缓存起来,方便下次直接使用。如果计算属性方法内部所有的任何数据都没有发生改变,则不会重新对计算属性求值
watch、methods、computed对比
- 三者内部定义的都是function,在computed中要return一个值,methods更注重业务逻辑,computed适合数据计算
- computed:结果会被缓存,除非依赖的属性变化才会重新计算。计算属性当作属性来使用。适用于数据操作
- methods:表示一个具体的操作,主要是业务逻辑。适用于方法调用
- watch:一个对象,键是需要观察的表达式,值对应回调函数,主要用来监听某些特定的数据的变化,从而进行某些具体的业务逻辑操作,可看作是computed和methods的结合体。适用于监听虚拟的