本文章会分析两则关于不常见又好事的两个小技巧,也同时会从源码的角度进行解析,告诉大家为什么这么写是可以的
1. this.$on(‘hook:beforeDestroy’, fn) 使用技巧
1.1 使用案例
1.1.1 bad案例
// 定义部分-----------------------------------------------
let timer = null
let timerForRequest = null // ※※※
// data部分---------------------------------------------
mounted() {
this.currentTime()
this.getSchedule()
// 判断是否全屏
this.judgeFullScreen()
window.onresize = () => {
const navButton = document.getElementById('toggleModelBtn')
if (document.documentElement.clientHeight >= 1080 && !isNavHide) {
navButton.click()
isNavHide = true
}
if (document.documentElement.clientHeight < 1080 && isNavHide) {
navButton.click()
isNavHide = false
}
}
timerForRequest = setInterval(() => { // ※※※
this.getSchedule()
}, 60 * 1000)
}
// beforeDestroy 声明周期----------------------------------
beforeDestroy() {
clearInterval(timer)
clearInterval(timerForRequest)
cancelAnimationFrame(this.raf)
timer = null
timerForRequest = null // ※※※
this.raf = null
}
- 请注意上述代码中定时器定位的变量,以及清除变量的位置。上述的写法是我们常规的写法,从逻辑的角度来看没有任何问题,那为什么我们说是坏的案例呢
- 变量
timerForRequest
在上述代码中出现了多次,只是为了定时器清除,虽然逻辑没有问题,但是代码有点冗余
1.1.2 good案例
let timerForRequest = setInterval(() => {
this.getSchedule()
}, 60 * 1000)
this.$on('hook:beforeDestroy', () => {
clearInterval(timerForRequest)
// 推荐写法 ※※※
timerForRequest = null
})
- 上述的写法
this.$on('hook:beforeDestroy')
也许有部分的人知道,但是今天我们探究的是原理,从源码的角度来看下为什么这么写是可以的
1.2 源码解析
- 解析这个源码的同时我们会简单的说下vue的生命周期的实现过程,因为这些技巧都是在生命周期调用范围内发生的
这里先简单提供一个思路,关于上述定时器的销毁,刚开始的时候我们是单独定义一个生命钩子来做销毁操作,现在我们不这么做了。我们可以定义一个方法,目的是调用生命钩子方法的时候,顺便执行下我们的方法不就好了
- 先看下生命周期是如何实现的
Vue.mixin({
created: () => {
console.log('我是全局钩子函数') // 第一次执行
}
})
const vm = new Vue({
el: '#app',
created() {
console.log('我是组件钩子') // 第二次执行
}
})
- 通过上述截图可以看到,混入生命钩子以及自身的钩子都会在实例this上进行挂载,执行的时候直接在this上获取就行,接下来看下调用位置
- 上述的截图是生命钩子调用的位置,其实就是调用了函数
callHook
, 但是函数中定义了vm.$emit('hook' + hook)
很重要,跟我们说的this.$on('hook:beforeDestroy', fn)
不谋而合了。其实这种现象可以理解为发布订阅,自身的vue文件中进行订阅,在生命钩子执行的同时进行触发。
2. 多余的watch
2.1 案例分析
2.1.1 bad案例
// watch定义部分 -------------
watch: {
table(value) {
this.tranformTable(value, 0.3)
}
}
// 方法定义部分 ------------
method: {
tranformTable(element, speed) {
const callback = () => {
const tableHeight = element.clientHeight
if (this.tableTop < tableHeight) {
this.tableTop = this.tableTop + speed
} else {
this.tableTop = 0
}
this.raf = requestAnimationFrame(callback)
}
callback()
}
}
- 通过上述的代码可以看到,直接在method中定义方法,watch中监听某个属性当属性发生变化的同时,直接调用之前定义的方法
2.1.2 good案例
watch: {
table: 'tranformTable'
}
method: {
tranformTable(element, speed = 0.3) {}
}
- 上述的代码实现更简单,可以在watch的位置使用字符串
2.2 源码解析
- 其实这个源码原理相对简单
- 就是watch对应的value值可以是对象/ 函数/ 字符串。 但是如果是字符串的话,这个字符串必须是methods中的方法,这样调用的时候可以通过this直接调用函数
3. 结语
好了,今天就是为了给大家分析两个小技巧,虽然网上有很多这种技巧但是这种技巧如何成立的并没有说明。希望能对看到的小伙伴有所帮助… 我们下篇再见啦!!!