一、组件的生命周期
组件创建阶段:
一个组件以标签的形式使用时,就会立即创建一个组件实例,new Vue()。在内存中初始化这个组件对应的基本事件和生命周期函数。初始化完成后会立即触发beforeCreate生命周期函数。
beforeCreate阶段:就是初始化组件的Vue实例,此时组件的props/date/methods等还没有被创建,都处于不可用的状态,也就是说props和data里面的数据不能访问,methods里面的方法不能调用。
在beforeCreate生命周期函数之后会初始化props/date/methods。初始化完成后会立即触发created生命周期函数。
created阶段:组件的props/date/methods都已经被创建好了,并且都是可用状态。但是此时的模板结构还没有生成,vm.$el没有创建,不能操作DOM。在这个阶段可以在methods中发起Ajax请求,把请求回来的数据保存在date中,在created里面通过this调用,之后供template模板渲染的时候使用。
在created生命周期函数之后有一个判断,判断是否有el选项,如果有el选项就继续判断是否有template选项。如果没有el选项,就会判断当vm.$mount(el)这个方法被调用的时候,再判断是否有template选项,如果有template选项就编译template选项。如果没有就会把el提供的区域基于数据和模板在内存中去编译生成HTML结构。(通过package.json文件中的"vue-template-compiler"vue模板编译器把.vue文件编译生成JavaScript脚本文件后,交给浏览器去执行。)编译好HTML结构后,会自动触发beforeMount生命周期函数。
beforeMount阶段:将要把内存中编译好的HTML结构渲染到浏览器中,此时浏览器还没有当前组件的DOM结构,只是在内存中,不能操作DOM。
beforeMount执行完后,用内存中编译生成的HTML结构替换el属性指定的DOM元素。之后会自动触发mounted生命周期函数。
mounted阶段:内存中编译好的HTML结构已经在浏览器中渲染完成。可以在此时操作DOM。此时浏览器中已经包含了当前组件的DOM结构。最早操作DOM元素可在此阶段进行。
当进行到mounted阶段说明一个组件已经创建成功,可以供用户去访问。
组件运行阶段:
beforeUpdate阶段:当页面的DOM结构发生变化时,将要根据最新的数据重新渲染页面的DOM结构。此时data里面的数据是最新的,但是页面的dom结构未更新还是旧的。
updated阶段:已经根据最新的数据重新渲染组件的DOM结构。此时data里面的数据是最新的,页面的dom结构也是最新的。此时可以操作最新的DOM。
组件销毁阶段:
beforeDestory阶段:组件将要销毁,此时组件还存在,仍然处于可用的状态。
destory阶段:组件已经被销毁,组件在浏览器中对应的DOM结构已经被移除。
最常用的生命周期函数是:created和mounted。
beforeCreate、created、beforeMount、mounted、beforeDestory、destory生命周期函数在一个组件生命周期里进行1次。
beforeUpdate和updated生命周期函数在一个组件生命周期里可进行0次或n次。
二、缓存路由(keep-alive) 及新的生命周期
keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
属性:
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例(需要知道组件的 name,项目复杂的时候不是很好的选择,以下有个例子缓存组件)
// 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存aa组件 <keep-alive include="aa,bb" exclude="bb">
<component />
</keep-alive>
生命周期:
activated :路由组件被激活时触发。(当进入缓存的路由组件时触发)而activated第一次创建页面时不会激活,缓存之后,第二次进入才会开始激活
deactivated:路由组件失活时触发。(当离开缓存的路由组件时触发)
例子:
1、结合路由meta缓存页面
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
let routes = [
//默认展示组件
{
path: '/',
redirect:"/index",
component: () => import('@/components/orgIndex/index.vue'),
},
{
path:"/index",
component: () => import('@/components/orgIndex/index.vue'),
children:[
{
path:"/",
component: () => import('@/components/orgIndex/mycontent/content.vue'),
meta: {
keepAlive: true // 需要缓存,
}
},
{
path:"orgdetail",
name:"orgdetail",
component: () => import('../components/orgIndex/org/orgdetail.vue'),
meta: {
keepAlive: false, // 不需要缓存,
isRefresh: true,
}
},
]
},
]
const router = new Router({
routes
})
router.beforeEach((to,from,next) => {
window.scrollTo(0,0)
next()
}
)
router.afterEach((to,from)=>{
// window.scrollTo(0,0)
})
// 解决报错
const originalPush = Router.prototype.push
const originalReplace = Router.prototype.replace
// push
Router.prototype.push = function push (location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
// replace
Router.prototype.replace = function push (location, onResolve, onReject) {
if (onResolve || onReject) return originalReplace.call(this, location, onResolve, onReject)
return originalReplace.call(this, location).catch(err => err)
}
export default router
//被缓存的视图组件
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
//不被缓存的视图组件
<router-view v-if="!$route.meta.keepAlive"></router-view>
2、页面回到上次浏览位置
//离开页面之前将高度存储到sessionStorage。这里不建议用localStorage,因为session在关闭浏览器时会自动清除,而local则需要手动清除,有点麻烦。beforeRouteLeave(to,from,next){
sessionStorage.setItem('scrollH',document.getElementById('demo').scrollTop)
next()
},//在activated生命周期内,从sessionStorage中读取高度值并设置到dom
activated(){
if(sessionStorage.getItem('scrollH')){
document.getElementById('demo').scrollTop=sessionStorage.getItem('scrollH')
}
},