生命周期、钩子函数、路由
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:以下是本篇文章正文内容,下面案例可供参考
一、生命周期
1、生命周期的基本定义
生命周期: Vue是一个构造函数,当执行执行这个函数时,相当于初始化vue实例; 在创建实例过程中,需要设置数据监听,编译模板,将实例挂载到DOM上,数据更新能够让DOM也更新,在这个初始化,又会不同阶段默认调用一些函数执行,这些函数就是生命周期的钩子函数;
2、钩子函数
钩子函数 | 简单介绍 |
---|
beforeCreate | 在内存开始创建组件之前,数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了 | created | 在内存把组件创建完后,在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来 | beforeMount | 在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已,在数据渲染到页面之前 | Mounted | 数据已经真实渲染到页面上 在这个钩子函数里面我们可以使用一些第三方的插件 | beforeUpdate | 表示页面还没有被更新,数据已经被更改了,页面显示的数据还是旧的,没有被改变,而data中的数据是更改后的数据,所以数据不一致。 | Update | 数据变化后,事件执行的时候,页面和data数据已经保持一致了,都是最新的 | beforeDestroy | 实例(组件)被销毁之前调用 | Destroyed | 当执行到destroyed函数的时候,组件已经被完全销毁了,此时,组件中的所有数据,方法、指令过滤器都已经不可用了。 |
注意 :
- 发送Ajax请求时,应在create执行期间发送
- 操作DOM元素,应在Mounted函数期间操作元素
代码示例
<template>
<div>
<p>首页</p>
<span>{{username}}</span>
</div>
</template>
<script>
export default {
name:'Main',
data(){
return {
username:'Hello',
}
},
beforeCreate(){
console.log(this.username);
},
created(){
console.log(this.username);
},
beforeMount(){
console.log('初始页面被渲染了')
},
mounted(){
this.username='你好';
console.log(this.username);
},
beforeUpdate(){
console.log('页面数据更新了');
},
updated(){
console.log('更新的页面数据被渲染了');
}
}
</script>
<style>
</style>
二、路由
1.路由的基本概念
- 路由的定义?
路由本质上来说就是一种对应关系,比如说我们在浏览器中输入不同的 url 地址,我们就能访问不同的资源,那么这 url 地址与资源之间的对应关系,就是路由。
- 路由的分类
- 后端路由:指请方式、请求地址、与函数function处理函数之间的对应关系
- 前端路由:前端路由是通过页面 hash 值(锚链接) 的变化实现的不同页面之间的相互切换,本质上是用户事件与事件处理函数之间的对应关系
? 前端路由的核心就是监听事件并分发执行事件处理函数,所以需要依靠 window.onhashchange 事件来监听 hash 值的变化,以及 location.hash 获取目前页面的 hash 值。
- SPA
? SPA(Single Page Application)单页面应用程序,整个页面只有一个页面,内容的变化通过 ajax 局部更新实现,同时支持浏览器地址栏的前进与后退操作,又称单页面多视图。其实现原理是基于 url 地址的hash变化,hash变化会导致浏览器访问记录的变化,但不会触发新的url请求。SPA最核心的技术点就是前端路由。
代码示例:
<template>
<div id="app">
<a href="#/main">首页</a>
<br>
<a href="#/movie">电影</a>
<component :is="comName"></component>
</div>
</template>
<script>
import Main from './components/main.vue'
import Movie from './components/movie.vue'
export default {
name: 'App',
components: {
Main,Movie,
},
data(){
return {
comName:'',
}
},
created(){
window.onhashchange=()=>{
switch(location.hash){
case'#/main':
this.comName='Main';
break;
case'#/movie':
this.comName='Movie';
break;
}
}
}
}
</script>
<style>
</style>
2、vue-router
1、vue-router的基本使用
- vue-router的含义
vue-router是vue.js官方给出的路由解决方案,他只能结合vue项目进行使用,能够轻松管理SPA项目中的组件切换 - vue-router的使用
点击此链接查看安装步骤 代码示例: index.js main.js App.vue
2、路由重定向
在用户访问某个地址A时,强制用户跳转到地址 B,并展示相关内容。想要实现重定向,需要使用路由规则的 redirect 属性。我们一般通过路由重定向为页面设置默认展示的组件。
<script>
const router = new VueRouter({
routes:[
{path:'/',redirect:'/page1'},
{path:'/page1',component:Main},
{path:'/movie',component:Movie}
],
})
</script>
3、嵌套路由
? 路由嵌套是指:当我们点击父级路由链接,在路由占位符显示的组件内容中有子级路由链接,点击子级路由链接时,在子级路由占位符显示子级组件内容。子级路由规则,由父级路由的 children 属性来配置。
- 首先在嵌套组件中的负组件中声明子路由链接和子路由占位符
<template>
<div>
<p>欢迎大家的到来</p>
<span class="bottom">
<router-link to='/page1/1'>电视剧</router-link>
<router-link to='/page1/2'>电影</router-link>
<router-view></router-view>
</span>
</div>
</template>
<script>
export default {
name:'Main'
}
</script>
<style>
.bottom{
width: 300px;
height: 100px;
display: block;
background-color: rgb(198, 236, 185);
}
</style>
- 然后通过children属性声明子路由规则(数组的形式),并在index.js的文件中导入所需要的子组件,并用children声明规则
import Vue from 'vue'
import VueRouter from 'vue-router'
import Main from '../components/page1.vue'
import Movie from '../components/movie.vue'
import Paper1 from '../components/paper1.vue'
import Paper2 from '../components/paper2.vue'
Vue.use(VueRouter)
const router = new VueRouter({
routes:[
{path:'/',redirect:'/page1'},
{path:'/page1',component:Main,children:[
{path:'/page1',component:Paper1},
{path:'/page1/1',component:Paper1},
{path:'/page1/2',component:Paper2}
]},
{path:'/movie',component:Movie}
],
})
export default router
补充:
在嵌套路由中,子路由和父路由之间如何传值?
①、虽然是通过路由嵌套的方式展示的页面,当其形式还是相当于父子组件的的关系,所以我们可以通过父子组件传值的方式来传值,只不过是将router-view视为子组件在父组件中的载体, 使用this.$emit来传参
②、父路由也可以给子路由传递数据,用props
互相调用参数
①、子路调用父路中的参数,用this. $emit ,或直接使用this. $parent来进行调用
②、父路调用子路可直接使用this.$ref来进行调用
4、动态路由匹配参数(路由传参)
- this.route.$params.参数
设置路由规则时,在路径path里,通过 /:参数 的形式,设置参数。然后在组件中通过 {{ $route.params.参数 }} 的形式,获取参数。该方法耦合度高,不够灵活,很少使用。
<template>
<div>
<p>电影</p>
<p>{{$route.params.id}}</p>
</div>
</template>
const router = new VueRouter({
routes:[
{path:'/',redirect:'/page1'},
{path:'/page1',component:Main,children:[
{path:'/page1',component:Paper1},
{path:'/page1/:id',component:Movie},
{path:'/page1/:id',component:Movie}
]},
{path:'/movie',component:Movie}
],
})
- 使用props
- props 的值为 true
在路由规则中,将props的值设置为 true,使 $route.params 成为组件属性。在路径path里,通过 /:参数 的形式,设置参数,然后在组件中,使用 props 接收参数即可。
const User = {
props: ['id'],
template: '<h1>User 组件 -- 用户id为: {{id}}</h1>'
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/user'},
{ path: '/user/:id', component: User, props: true },
]
})
- props的值为对象
? 我们将props 的值设置为一个对象,就相当于将对象中的所有属性传递给组件,组件使用 props[‘属性名1’,‘属性名2’] ,即可接收数据
const User = {
props: ['id', 'uname', 'age'],
template: '<h1>User 组件 -- 用户id为: {{id}} -- 姓名为:{{uname}} -- 年龄为:{{age}}</h1>'
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/user'},
{ path: '/user/:id', component: User, props: { uname: 'lisi', age: 20 } }
]
})
- props的值为函数
? 如果既想获取路径传递的参数值,又想获取传递的对象数据,那么props应该设置为函数形式。
const User = {
props: ['id', 'uname', 'age'],
template: '<h1>User 组件 -- 用户id为: {{id}} -- 姓名为:{{uname}} -- 年龄为:{{age}}</h1>'
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/user' },
{
path: '/user/:id',
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })
},
{ path: '/register', component: Register }
]
})
5、命名路由(?嵌套的路由中能否使用命名路由)
? 为了更加方便的表示路由的路径,我们可以给路由规则起一个别名,即为命名路由。
<!-- to属性动态绑定一个对象 name属性 表示要绑定的路由规则 params 表示要传递的参数 参数名必须与路由规则定义的相同 -->
<router-link :to="{ name: 'user', params: {id: 3} }">User3</router-link>
<!-- <router-link to="/user/3">User3</router-link> -->
<script>
const User = {
props: ['id', 'uname', 'age'],
template: '<h1>User 组件 -- 用户id为: {{id}} -- 姓名为:{{uname}} -- 年龄为:{{age}}</h1>'
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/user' },
{
name: 'user',
path: '/user/:id',
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })
}
]
})
</script>
6、编程式导航
? 页面导航分为两种方式:声明式导航和编程式导航。通过点击链接实现导航的方式,叫做声明式导航,比如:网页中的 a 超连接 或者 vue router 里面的 标签。通过调用 JavaScript 形式的API实现导航的方式,叫做编程式导航,比如:网页中的location.href 。
vue Router 中常用的编程式导航 API 有:
- this.$router.push()
? 该API的参数形式有很多:
? ① 路径字符串,例如:this.$router.push(‘/user’)。
? ② 路径对象,例如:this.$router.push({path: ‘/user’})。
? ③ 命名路由对象,例如:this.$router.push({name: ‘/user’})
? ④ 带查询参数,变成 /user?uname=lisi的形式,例如:this.$router.push({ path: ‘/user’,query: { uname } })
<template>
<div>
<p>电影</p>
<button @click="handleclick()">点击跳转</button>
</div>
</template>
<script>
export default {
name:'Movie',
methods:{
handleclick(){
this.$router.push({path:'/number1'});
}
}
}
</script>
<style>
</style>
7、导航守卫
导航守卫是用来控制路由的访问权限,比如可以结合token 检查用户是否登录,当未登录的用户想要访问某些页面时,通过路由导航将其跳转到登录页面。vue-router 的导航守卫有全局前置守卫、全局解析守卫、路由独享的守卫等等等
- ① 全局前置守卫:
? 当给项目设置了全局前置守卫之后,在每次发生路由的导航跳转时,都会触发。所以开发者可以在全局前置守卫中,对路由的访问权限进行控制。
const router = new VueRouter({....})
router.beforeEach((to,from,next) => {
})
基本使用
const router = new VueRouter({....})
const pathArr = ['/home', '/home/users', '/home/rights']
router.beforeEach(function(to, from, next) {
if (pathArr.indexOf(to.path) !== -1) {
const token = localStorage.getItem('token')
if (token) {
next()
} else {
next('/login')
}
} else {
next()
}
})
- ② 组件内的守卫钩子函数
组件内的守卫钩子函数是指写在某一页面组件内的钩子函数,只有当页面的路由变化与该组件相关时才会调用执行。一同提供了三种钩子函数,适用于各种不同的场景: beforeRouteEnter(to,from,next) 该守卫钩子函数是在要跳转该组件对应的路由(或该组件对应路由的子路由)并且在该组件渲染之前调用执行的。第一个参数 to 表示要跳转到的路由信息对象,常用属性为 to.path 可以获取到要跳转到的路由地址。第二个参数from 表示要跳转离开的路由信息对象。因为该守卫函数执行时,组件实例还没有被创建,所以不能获取组件的this ,也就是无法获取或改变组件中的数据,但我们可以通过给第三个参数 next 传递一个回调函数,该函数的参数就是组件实例,通过这种方式来操作组件中的数据:
beforeRouteEnter (to, from, next) {
next((vm) => {
console.log(vm.a);
})
},
data() {
return {
a: 1
}
}
beforeRouteUpdate(to,from): 该守卫钩子函数是在当前路由发生了改变但该组件被复用时调用执行,经过我的实验,只有在动态路由这一种情况下,该方法才会被执行,举例来说就是:如果一个路由地址定义为:/course/:id,当路由地址从/course/1 跳转到 /course/2 时,该守卫钩子函数才会被执行。函数的两个参数与beforeRouteEnter(to,from) 意义相同,但此时组件实例已经创建好了,所以在该守卫钩子函数里面可以操作组件中的数据:
beforeRouteUpdate(to,from){
console.log(this.a);
},
data() {
return {
a: 1
}
}
beforeRouteLeave(to,from): 该守卫钩子函数是在跳转离开该组件时调用执行,也可以直接操作组件中的数据。函数的两个参数与beforeRouteEnter(to,from) 意义相同,这个守卫钩子函数通常用来预防用户在还未保存修改前突然离开的情况,可以通过return false 来取消路由跳转,让页面不变:
beforeRouteUpdate(to,from){
const answer = window.confirm('你还有未保存的内容,是否要离开本页面?')
if (!answer) return false
}
|