好久不见了,在研一结束一周后就匆匆忙忙开启了漫长的日常实习生活。无数次面试被挂的经验告诉我,只是简单的明白怎么用 API 是不够进入大厂的。因此,还是老方法,「用输出倒逼输入」,为了解决惰性带来的浅入浅出的问题,我依然决定拿时间换能力。这里会总结并分享一些我在实际开发过程中遇到的一些困惑和相关的探索。 感谢 ChatGPT 对本文的大力支持!🤖️

v-ifv-show 有什么区别?

Conditional Rendering | Vue.js (vuejs.org)

  • 两者本身都是控制动态渲染组件
  • 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

解决方案:

  1. lazyRender 属性设置为 false,这个时候 Popup 组件在 Mount 的时候就会全部加载。理论上会对性能有轻微的影响。
  2. Popup 组件内手动 Watch 一下 show 属性,在 show 属性发生变化的时候,对应的 ref 就是能正常引用的。

高度不定的元素该怎么设计 transition 动画?

问题分析:height: auto/100% 不会触发过渡动画,因为 transition 的过渡动画需要元素拥有确定的高度(即通过已知的起点和终点来计算逐帧的变化),例如 height: 300px => height: 100px

解决方案:

  1. max-height:可以为高度不定的元素设定 max-height 值,transition 动画会根据这个值的变化来进行渲染过渡的动画。局限:当目标高度比 max-height 小的时候,实际的过渡动画持续时间会小于手动设定的 transition 持续时间。
  2. grid:grid 布局的尺寸计算是根据最小高度来计算的,支持在 0fr => 1fr 的时候应用过渡动画。通过设定 grid 内容器样式的 min-height 设定展开前动画。

Vue 里的 nextTick 的触发时机?

nextTick 函数用于实现在下次 DOM 更新循环结束之后延迟回调,回调时机是当前 JS 执行结束之后,在下一个 DOM 更新循环之前。在 nextTick 之后,可以访问更新后的 DOM,比如元素的新尺寸或者位置等。在 JS 的事件循环中,nextTick 属于是微任务。

我们在实际开发过程中,常用的几个异步函数,分别是 promise(微), nextTick(宏/微), requestAnimationFrame(宏), setTimeout(宏),执行顺序是怎样的?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// promise => nextTick => requestAnimationFrame => timeout
nextTick(() => {
console.log("nextTick");
});

setTimeout(() => {
console.log("timeout");
}, 0);

requestAnimationFrame(() => {
console.log("requestAnimationFrame");
});

Promise.resolve().then(() => {
console.log("promise");
});

Vue 中的 computed 和 watch 是怎么实现的,分别适合怎样的场景?

core/packages/reactivity/src/computed.ts at main · vuejs/core (github.com)

computed 方法依赖于 ComputedRefImpl 类来创建了一个可以自定义 gettersetter 方法的响应式 ref。为了实现响应式的更新,ComputedRefImpl 类中又通过 ReactiveEffect 类新建了 effect 实例来管理 value 的更新。

core/packages/runtime-core/src/apiWatch.ts at main · vuejs/core (github.com)

watch 方法通过指定 sourcecallback 来实现更加直观的响应式更新,对于 source 而言,watch 方法会根据是 ref/reactive/array/function 来设置不同的 getter
方法内部通过 EffectScheduler 类的实例来管理 callback 的调用时机,默认是 render 前,但是还可以设定为同步或者 render 后。
watch 方法和 computed 方法一样,使用 ReactiveEffect 类,来实现响应式更新。

这两个方法原理类似,使用场景稍微有些不同,computed 适用于比较直接的根据其他响应式数据计算结果,自带缓存。watch 的控制更加细粒度,通过监听数据的变化,执行特定的逻辑。