ResizeObserver与nextTick的使用区别
前端页面开发经常会遇到需要对页面元素进行大小调整和控制DOM更新顺序的场景。这时候,ResizeObserver
和nextTick
就派上用场了。今天,咱们就来详细了解一下这两个工具的用途、用法以及实际应用场景。
一、ResizeObserver详解
(一)ResizeObserver是什么
ResizeObserver
,从名字就能大概猜到,它是一个用来观察元素大小变化的工具。在实际开发中,我们常常需要根据元素大小的改变来动态调整页面布局或者执行一些特定的操作,ResizeObserver
就为我们提供了这样的能力。
(二)ResizeObserver的基本用法
使用ResizeObserver
很简单,通过new ResizeObserver(fn)
来创建一个观察者实例,这里的fn
是一个回调函数。这个回调函数默认会接受一个数组作为参数,数组的第一项就是我们传入需要观察大小变化的DOM元素。在回调函数内部,就可以根据元素大小的变化来编写相应的逻辑。
比如下面这段代码:
// 创建一个ResizeObserver实例,回调函数会在观察的元素大小改变时执行 const observer = new ResizeObserver(entries => { // 遍历传入的entries数组,entries包含了所有被观察元素的大小变化信息 for (let entry of entries) { console.log('entry:', entry); // 减去导航栏高度和卡片高度,动态设置目标元素的高度 (entry.target as HTMLElement).style.height = (window.innerHeight - 55 - 290) + 'px'; } })
在这段代码里,ResizeObserver
会监听目标元素的大小变化,一旦变化发生,就会执行回调函数,根据窗口的高度减去固定的导航栏和卡片高度,来动态调整目标元素的高度。
(三)在Vue中的使用
在Vue项目中使用ResizeObserver
时,需要注意在合适的时机打开和关闭观察者。一般在组件挂载(onMounted
)时开始观察,在组件卸载(onUnmounted
)时停止观察。
// 组件挂载时执行的回调函数 onMounted(() => { // 使用nextTick确保DOM更新完成后再进行观察操作 nextTick(() => { // 判断expanded.value是否有值,有的话开始观察domRef.value对应的元素 if (expanded.value.length) { observer.observe(domRef.value) } }) }) // 组件卸载时执行的回调函数 onUnmounted(() => { // 停止观察,释放资源 observer.disconnect() })
这里通过nextTick
确保DOM已经渲染完成后,再让ResizeObserver
开始观察目标元素。而在组件卸载时,调用observer.disconnect()
停止观察,避免内存泄漏。
(四)获取DOM大小的相关API
在使用ResizeObserver
的过程中,常常会涉及到获取DOM元素大小的操作。其中,window.innerHeight
可以获取视口的高度,这在动态计算元素大小时非常有用。
(五)获取slot传进来的DOM
在Vue中,有时需要获取通过slot
传进来的DOM元素。比如:
<div ref="slotContainer" class="slot-container"> <slot></slot> </div>
// 使用template ref获取slot容器元素 const slotContainer = ref<HTMLElement>() // 获取slot内容的函数 const getSlotContent = () => { // 返回slot容器的第一个子元素 return slotContainer.value?.firstElementChild as HTMLElement }
需要注意的是,不能把ref
直接写到template
和slot
上面,而是通过这种方式获取slot
容器元素,进而操作其内部的子元素。
二、nextTick的用途
nextTick
在Vue开发中也扮演着重要的角色。虽然它在某些场景下的用途不太明显,但在涉及到多个UI调整且需要控制执行顺序时,它的作用就凸显出来了。
比如有这样一个需求:先将当前DOM移到视口顶部,再在DOM后面插入一个div
。在Vue中,由于有搜集响应式机制,最后才会触发更新。如果不使用nextTick
,可能就不会有中间的动画过程。下面这段代码展示了如何使用nextTick
来实现这个需求:
// 处理点击事件的函数 const handleClick = async () => { if (props.isActive) { emit('activate', null); // 关闭激活项 placeholderHeight.value = 0; return; } emit('activate', props.id); // 激活当前项 placeholderHeight.value = getDetailHeight(); // 等待DOM更新完成 await nextTick(); // 滚动到顶部 const itemEl = itemRef.value; if (itemEl) { itemEl.scrollIntoView({ behavior: 'smooth', block: 'start' }); } };
在这段代码里,当点击事件触发后,先执行了一些逻辑操作,然后通过await nextTick()
等待DOM更新完成,再执行将元素滚动到视口顶部的操作。这样就保证了先插入DOM,再进行滚动的顺序,从而实现了预期的动画效果。
总之,ResizeObserver
和nextTick
在前端开发中都有着各自独特的用途。ResizeObserver
让我们能够方便地监听元素大小变化并做出相应调整,而nextTick
则帮助我们控制DOM更新的顺序,确保复杂UI操作的正确执行。想必看到这里你已经掌握了吧~