十万个为什么「前端版」
好久不见了,在研一结束一周后就匆匆忙忙开启了漫长的日常实习生活。无数次面试被挂的经验告诉我,只是简单的明白怎么用 API 是不够进入大厂的。因此,还是老方法,「用输出倒逼输入」,为了解决惰性带来的浅入浅出的问题,我依然决定拿时间换能力。这里会总结并分享一些我在实际开发过程中遇到的一些困惑和相关的探索。 感谢 ChatGPT 对本文的大力支持!🤖️
v-if
和 v-show
有什么区别?
- 两者本身都是控制动态渲染组件
v-if
是真实的条件渲染,会在切换过程中销毁和重建块内的事件监听器和子组件。v-if
也是惰性的,如果初次渲染时为false
,就什么都不会做,直到为true
时才会局部编译。v-show
只是单纯的 CSS 样式切换,具体来说就是display: none
的开关。v-if
切换开销更高,v-show
的初始渲染开销更高。如果需要频繁切换,就用v-show
;如果运行时绑定条件很少改变,就用v-if
为什么 vant 库里的 Popup 组件的 onMounted 里面无法捕获到 ref?
问题分析:通过查看 vant 库的文档和源码,发现这个组件默认设置了 lazyRender
,通过监听 props.show
决定是否要 render 对应的 DOM 结构。我们主组件 mount 的时候,虽然也会 mount Popup
组件,但是这个时候 Popup
组件的 DOM 树是空的,在 onMounted
钩子里拿到对应的结点引用为 undefined
。
解决方案:
- 把
lazyRender
属性设置为false
,这个时候Popup
组件在 Mount 的时候就会全部加载。理论上会对性能有轻微的影响。 - 在
Popup
组件内手动Watch
一下show
属性,在show
属性发生变化的时候,对应的ref
就是能正常引用的。
高度不定的元素该怎么设计 transition 动画?
问题分析:height: auto/100%
不会触发过渡动画,因为 transition
的过渡动画需要元素拥有确定的高度(即通过已知的起点和终点来计算逐帧的变化),例如 height: 300px => height: 100px
。
解决方案:
- max-height:可以为高度不定的元素设定
max-height
值,transition
动画会根据这个值的变化来进行渲染过渡的动画。局限:当目标高度比max-height
小的时候,实际的过渡动画持续时间会小于手动设定的transition
持续时间。 - grid:grid 布局的尺寸计算是根据最小高度来计算的,支持在
0fr => 1fr
的时候应用过渡动画。通过设定 grid 内容器样式的min-height
设定展开前动画。
Vue 里的 nextTick 的触发时机?
nextTick
函数用于实现在下次 DOM 更新循环结束之后延迟回调,回调时机是当前 JS 执行结束之后,在下一个 DOM 更新循环之前。在 nextTick
之后,可以访问更新后的 DOM,比如元素的新尺寸或者位置等。在 JS 的事件循环中,nextTick
属于是微任务。
我们在实际开发过程中,常用的几个异步函数,分别是 promise(微), nextTick(宏/微), requestAnimationFrame(宏), setTimeout(宏)
,执行顺序是怎样的?
1 | // promise => nextTick => requestAnimationFrame => timeout |
Vue 中的 computed 和 watch 是怎么实现的,分别适合怎样的场景?
core/packages/reactivity/src/computed.ts at main · vuejs/core (github.com)
computed
方法依赖于 ComputedRefImpl
类来创建了一个可以自定义 getter
和 setter
方法的响应式 ref。为了实现响应式的更新,ComputedRefImpl
类中又通过 ReactiveEffect
类新建了 effect
实例来管理 value
的更新。
core/packages/runtime-core/src/apiWatch.ts at main · vuejs/core (github.com)
watch
方法通过指定 source
和 callback
来实现更加直观的响应式更新,对于 source
而言,watch
方法会根据是 ref/reactive/array/function
来设置不同的 getter
。
方法内部通过 EffectScheduler
类的实例来管理 callback
的调用时机,默认是 render
前,但是还可以设定为同步或者 render
后。watch
方法和 computed
方法一样,使用 ReactiveEffect
类,来实现响应式更新。
这两个方法原理类似,使用场景稍微有些不同,computed
适用于比较直接的根据其他响应式数据计算结果,自带缓存。watch
的控制更加细粒度,通过监听数据的变化,执行特定的逻辑。