前端路由和后端路由的概念

  • 后端路由: 对于普通网站,所有的链接都是URL地址,所有的URL地址都对应服务器上对应的资源

  • 前端路由: 对于单页面应用程序来说,主要通过URL的hash(#号),来实现不同页面之间的切换,同时,hash有一个特点,HTTP请求中不包含hash相关的内容,所以单页面程序中的页面跳转主要用hash来实现

在单页面应用程序中,这种通过hash改变切换页面的方式,称作前端路由(区别于后端路由)

vue-router

Vue-router3.0安装方式:

1
2
3
4
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)
  • 构建开发版
    1
    2
    3
    4
    git clone https://github.com/vuejs/vue-router.git node_modules/vue-router
    cd node_modules/vue-router
    npm install
    npm run build

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<div id="app">
<!-- 地址 -->
<p><font color="red">*</font>地址:<span>{{route_path}}</span></p>
<font color="red">地址无刷新不会变化,这也正印证了上边的特性</font>

<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link><br>
<router-view></router-view>
</div>
<template id="login">
<div>
<label>用户名</label>
<input type="text" name=""><br>
<label>密码</label>
<input type="text" name=""><br>
<button type="button">登录</button>
</div>
</template>
<template id="register">
<div>
<label>用户名:</label>
<input type="text" name=""><br>
<label>密码:</label>
<input type="text" name=""><br>
<label>确认密码:</label>
<input type="text" name=""><br>
<button type="button">注册</button>
</div>

</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//创建一个路由对象,当导入vue-router包之后,在window 全局对象中就有了一个路由构造函数 vueRouter
// 在new一个路由对象的时候,可以为构造函数,传递一个配置对象
var login = {
template:'#login'
}
var register = {
template:'#register'
}

var routerObj = new VueRouter({
routes:[
// 每个路由规则,都是一个对象,这个规则对象身上有两个必须的属性
// 1. path: 表示坚挺的路由链接地址
// 2. component 表示如果匹配则展示对应组件(必须是组件模板对象而不是组件名称)
{path:'/login',component:login},
{path:'/register',component:register},
] //表示路由匹配规则
})
var vm = new Vue({
el:'#app',
data:{
route_path: ''
},
methods:{
},
created(){
this.route_path = this.$route.path
},
components:{
login,
register
},
// 将路由规则对象,注册到vm实例上,用来监听URL地址的变化,然后展示对应的组件
router:routerObj
})

这样默认展示根路径 /,很别扭

1
2
3
4
5
6
7
8
9
10
var routerObj = new VueRouter({
routes:[
//表示路由匹配规则
// 重定向 / 的 url地址 利用redirect 不属于Node里的redirect
// 目的:手动修改哈希值
{path:'/',redirect:'/login'}
{path:'/login',component:login},
{path:'/register',component:register},
]
})

需求1:设置选中路由高亮

1
2
3
4
5
6
7
8
9
10
<style>
.router-link-active{
color:red;
font-weight:800;
font-style: italic;
font-size:20px;
text-decoration: underline;
background-color:green;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
var routerObj = new VueRouter({
routes:[
//表示路由匹配规则
// 重定向 / 的 url地址 利用redirect 不属于Node里的redirect
// 目的:手动修改哈希值
{path:'/',redirect:'/login'}
{path:'/login',component:login},
{path:'/register',component:register},
],
linkActiveClass:'myactive'
})

需求2: 为路由切换加入动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<style>
.v-enter,
.v-leave{
opacity: 0;
transform: translateX(140px)
}
.v-enter-active,
.v-leave-active{
transition: all 0.4s ease
}
</style>
<transition mode="out-in">
<router-view></router-view>
</transition>

路由规则中定义参数

  • $route.query
1
2
3
4
5
6
<div id="app">
<!-- 如果在路由中,使用传参,不需要修改path -->
<router-link to="/login?id=1&name=dong">登录</router-link>
<router-link to="/register">注册</router-link>
<router-view></router-view>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var login = {
template:'<h1>登录---ID:{{$route.query.id}}---用户:{{$route.query.name}}</h1>',
created(){
console.log(this.$route)
}
}
var register = {
template:'<h1>注册</h1>'
}
var router = new VueRouter({
routes:[
{path:'/',redirect: '/login'},
{path:'/login',component: login},
{path:'/register',component: register}
]
})
var vm = new Vue({
el:'#app',
data:{

},
methods:{},
router:router
})
  • $route.params
    1
    2
    3
    4
    5
    6
    <div id="app">
    <!-- 如果在路由中,使用传参,不需要修改path -->
    <router-link to="/login/:id">登录</router-link>
    <router-link to="/register">注册</router-link>
    <router-view></router-view>
    </div>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    var login = {
    template:'<h1>登录---{{$route.params.id}}</h1>',
    created(){
    console.log(this.$route)
    }
    }
    var register = {
    template:'<h1>注册</h1>'
    }
    var router = new VueRouter({
    routes:[
    {path:'/',component: login},
    {path:'/login/12',component: login},
    {path:'/register',component: register}
    ]
    })
    var vm = new Vue({
    el:'#app',
    data:{

    },
    methods:{},
    router:router
    })

路由的嵌套(children)

使用 children 属性 ,实现子路由,同时,子路由的path前面,不要带 / ,否则永远以根路径开始请求,这样不方便用户理解 url 地址

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
<router-link to="/account">Account</router-link>
<router-view></router-view>
</div>
<template id="temp1">
<div>
<h1>这是Account组件</h1>
<router-link to="/account/login">登录</router-link>
<router-link to="/account/register">注册</router-link>
<router-view></router-view>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var account = {
template:'#temp1'
}
var login = {
template:'<h4>登录</h4>'
}
var register = {
template:'<h4>注册</h4>'
}
var router = new VueRouter({
routes:[
{
path:'/account',
component:account,
children:[
{path:'login',component:login},
{path:'register',component:register}
]
}
// {path:'/account/login',component:login},
// {path:'/account/register',component:register}
]
})
var vm = new Vue({
el:'#app',
data:{},
methods:{},
router:router
})

使用命名视图实现经典布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<style type="text/css">
html,body{
margin: 0;
padding: 0
}
h1{
margin: 0;
padding: 0;
font-size: 16px
}
.header{
height: 80px;
background-color: orange
}
.container{
display: flex;
height: 600px;
}
.left{
background-color: lightgreen;
flex:2;
}
.main{
background-color: lightpink;
flex: 8
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="app">
<router-view></router-view>
<div class="container">
<router-view name="left"></router-view>
<router-view name="main"></router-view>
</div>
</div>
<template id="header">
<div class="header">
头部区域
</div>
</template>
<template id="leftBox">
<div class="left">
左边区域
</div>
</template>
<template id="MainBox">
<div class="main">
主区域
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var header = {
template:'#header'
}
var leftBox = {
template:'#leftBox'
}
var MainBox = {
template:'#MainBox'
}
var router = new VueRouter({
routes:[
// {path:'/',component: header},
// {path:'/left',component: header},
// {path:'/main',component: header},
{
path:'/',
components:{
'default': header,
'left': leftBox,
'main': MainBox
}
}
]
})
var vm = new Vue({
el:'#app',
data:{
},
methods:{},
router:router
})

效果链接

案例: keyup事件实现

方式1

1
2
3
4
5
6
<div id="app">
<!-- 监听文本框数据改变拼接成fullname -->
<input type="text" name="" v-model="firstname" @keyup="getFullName">+
<input type="text" v-model="lastname" name="" @keyup="getFullName">
<input type="text" v-model="fullname" name="">
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
var vm = new Vue({
el:'#app',
data:{
firstname:'',
lastname:'',
fullname:''
},
methods:{
getFullName:function(){
this.fullname = this.firstname+'-'+ this.lastname
}
},
})

效果

方式2

1
2
3
4
5
6
<div id="app">
<!-- 监听文本框数据改变拼接成fullname -->
<input type="text" name="" v-model="firstname">+
<input type="text" v-model="lastname" name="">
<input type="text" v-model="fullname" name="">
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var vm = new Vue({
el:'#app',
data:{
firstname:'',
lastname:'',
fullname:''
},
methods:{
},
watch:{
// 使用这个属性,可以监视watch data事件的变化,然后触发方法
'firstname':function(newVal,oldValue){
// this.fullname = this.firstname + '-' + this.lastname
this.fullname = newVal + '-' + this.lastname
},
'lastname':function(newVal){
this.fullname = this.firstname + '-' + newVal
}
}
})

方式3

1
2
3
4
5
6
<div id="app">
<!-- 监听文本框数据改变拼接成fullname -->
<input type="text" name="" v-model="firstname">+
<input type="text" v-model="lastname" name="">
<input type="text" v-model="fullname" name="" readonly>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var vm = new Vue({
el:'#app',
data:{
firstname:'',
lastname:'',
},
methods:{
},
computed:{
// 在computed 中,可以定义一些属性,这些属性叫做【计算属性】
// 本质是一个方法,计算的时候把名称直接当作属性来使用,并不会当作方法来调用
// 注意1: 计算属性,在引用的时候,一定不要加{}去调用,直接把他当作普通属性去使用就好了
// 注意2: 只要计算属性,这个function 内部,所用到的任何data的变化会 【重新计算】
// 注意3: 计算属性求值结果会缓存,方便下次直接使用,如果计算属性方法中,所有来的任何数据没发生变化,则不会重新对计算求值
'fullname': function(){
return this.firstname + '-' + this.lastname
}
}
})

通过 watch 监听路由变化

代码

1
2
3
4
5
6
7
8
<div id="app">
<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link>
<!--
需求:监听路由改变做出反应
-->
<router-view></router-view>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const login = {
template:'<h4>这是登录组件,这个组件是爸爸我开发的</h4>'
}
const register = {
template:'<h4>这是注册组件,这个组件是某某开发的</h4>'
}
const router = new VueRouter({
routes:[
{path:'/',component:login},
{path:'/login',component: login},
{path:'/register',component: register}
]
})
var vm = new Vue({
el:'#app',
data:{

},
methods:{},
router:router,
watch:{
'$route.path':function(newVal,oldVal){
// console.log(newVal+'-'+oldVal)
if (newVal==="/login") {
alert('欢迎进入登录页面^-^')
}else if(newVal === '/register'){
alert('欢迎进入注册页面^-^')
}
}
}
})

总结

  1. computed属性的结果会缓存,除非以来的响应式属性发生变化才会重新计算算,主要当作属性来用
  2. method 方法表示一个具体的操作,主要书写业务逻辑
  3. watch 一个对象,就是需要观察的表达式,主要用来监听某些特定数据的变化,,从而进行某些逻辑操作,可以视为 computed + method