一切的一切都是因为封装一个简单的进度条组件而引发的血案
起初的思路
这个组件设计起来很简单,这是起初的思路
<div class="bar" ref="bar">
<div class="contianer" :style="barStyle"></div>
</div>
</template>
props:{
progress:{
type:Number,
default:()=>0.3
}
},
computed:{
barStyle(){
const w=this.$el.clientWidth
return{
background:'#0176FF',
borderRadius:'4px',
height: '18px' ,
// width:'57px'
width:`${w*this.progress}px`
}
}
}
报错:
主要原因就是this.$el为undefined,也就是拿不到模板
新的改变
export default {
props:{
progress:{
type:Number,
default:()=>0.3
}
},
data(){
return{
offset:0
}
},
computed:{
barStyle(){
return{
background:'#0176FF',
borderRadius:'4px',
height: '18px' ,
width:`${this.offset}px`
}
}
},
mounted(){
this.setOffset(this.progress)
},
methods:{
setOffset(progress){
const w=this.$el.clientWidth
this.offset=w*progress
}
}
}
解决思路也很简单,维护了一个offset变量,用来计算偏移量。
computed执行了两次,第一次offset为0 第二次是在mounted之后offset为1
思考
- 为啥在computed中拿不到模板?computed执行时机是什么时候?
- watch执行时机是什么时候呢?是否可以拿到模板呢?
1.watch不开起立即监听,
在这个例子中监听offset的变化
watch:{
offset:{
handler(){
console.log('watch')
}
}
},
其他生命周期钩子也加上console
打印结果如下:
很明显 computed执行时机在页面首次渲染时是在beforeMount后 mounted之前
而watch是依赖发生变化才会执行(不开起立即监听情况),所以在mounted后offset改变了watch才会执行,而watch执行是优先于其他钩子的。computed也和初次渲染时执行情况类似,在beforeUpdate之后和updated之前,由此可见computed是永远拿不到最新的模板的。
2.watch开启立即监听
watch:{
offset:{
handler(){
console.log('watch')
},immediate:true
}
},
更加证明了之前的结论,watch执行时机是优先于其他钩子的,computed执行时机是在页面更新/渲染前 和页面更新/渲染 之间执行的。二者都拿不到最新的模板。