npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@deot/helper-resize

v1.1.6

Published

基于原生 `ResizeObserver` 监听元素尺寸变化,并在同一元素的多个实例之间复用 observer 和 listeners。

Downloads

774

Readme

@deot/helper-resize

基于原生 ResizeObserver 监听元素尺寸变化,并在同一元素的多个实例之间复用 observer 和 listeners。

安装

pnpm add @deot/helper-resize

使用

import { Resize } from '@deot/helper-resize';

const off = Resize.of(element).on(() => {
	return element.offsetWidth;
});

off();

也可以使用静态快捷方法或从聚合包导入:

import { Resize } from '@deot/helper';

const listener = () => {};
Resize.on(element, listener);
Resize.off(element, listener);

共用模式

默认每个元素一个 ResizeObserver:同时有 N 个元素变化,浏览器就回调 N 次,并且在每次回调之间清空微任务。传入 { shared: true } 后,以同一个监听函数注册的元素共用一个 ResizeObserver,它们的变化由一次回调带回:

import { Resize } from '@deot/helper-resize';

const listener = (entries) => {
	entries.forEach(({ target }) => {
		// target 为尺寸变化的元素
	});
};
elements.forEach(element => Resize.on(element, listener, { shared: true }));
elements.forEach(element => Resize.off(element, listener, { shared: true }));

// 或者一次删除该监听函数在所有元素上的监听,不必记下元素
Resize.disconnect(listener);
  • 适合同时监听一批元素(如列表的行、某个节点的各层祖先):增减元素不再新建 observer,调用方按微任务合并的处理也只触发一次。
  • 同一个监听函数在一次回调里只执行一次,即使它注册在多个元素上;收到的 ResizeObserverEntry[] 只包含它自己监听的元素。默认模式下监听函数不带参数。
  • 不同的监听函数各有各的 ResizeObserver,由浏览器分别回调:要合并处理的元素必须用同一个监听函数注册。
  • 一帧内可能不止一次回调:监听函数(或随后的微任务)又改变了更深层被监听元素的尺寸时,浏览器会在同一帧内再回调一轮。
  • 只能通过静态方法使用;实例方法 Resize.of(element).on() 始终是默认模式。
  • 与默认模式各自登记、互不影响:off 时必须传入相同的 options,否则删的是另一种模式下的监听(没有则忽略,不会报错)。
  • 同一个监听函数在同一个元素上重复注册只算一次。
  • 回调之前已被 off 的元素不会出现在 entries 里;一个都不剩时不回调。
  • 某个监听函数抛错不影响其它监听函数。
  • 监听的元素会增减时(如列表的行),调用方不必自己记下它们:结束时 Resize.disconnect(listener) 即可。
  • 漏掉 off / disconnect 时:监听函数还在用的期间,它监听的元素一直被引用着;监听函数和元素都不再被引用(如组件已销毁、元素已移出文档)后,observer 随它们一起被回收。元素仍在文档里的话监听会一直生效,仍需注销。

API

Resize

以元素为单位管理 ResizeObserver,实例方法与静态方法共享监听状态。

new Resize(element)

创建实例;复用元素上已有监听状态

| 参数 | 参数类型 | 返回值 | | --- | --- | --- | | element | HTMLElement | Resize |

Resize.of(element)

创建实例的工厂方法

| 参数 | 参数类型 | 返回值 | | --- | --- | --- | | element | HTMLElement | Resize |

Resize.on(element, listener, options?)

静态注册监听并返回解绑函数;共用模式下监听函数在该元素上首次注册时开始观察

| 参数 | 参数类型 | 返回值 | | --- | --- | --- | | element、listener、options | HTMLElement、(entries?) => any、{ shared?: boolean } | () => void |

Resize.off(element, listener?, options?)

删除指定监听;省略 listener 时删除全部(仅限 options 对应的模式)。共用模式下监听函数不再监听该元素后停止观察

| 参数 | 参数类型 | 返回值 | | --- | --- | --- | | element、listener、options | HTMLElement、(entries?) => any、{ shared?: boolean } | void |

Resize.disconnect(listener)

共用模式:删除该监听函数在所有元素上的监听;没有在监听时忽略

| 参数 | 参数类型 | 返回值 | | --- | --- | --- | | listener | (entries?) => any | void |

options

静态 on / off 的可选参数

| 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | shared | 是否使用共用模式 | boolean | false |

Resize.on(listener)

注册实例监听;首次注册时创建 ResizeObserver

| 参数 | 参数类型 | 返回值 | | --- | --- | --- | | listener | () => any | () => void |

Resize.off(listener?)

删除指定或全部监听;清空后断开 observer

| 参数 | 参数类型 | 返回值 | | --- | --- | --- | | listener | () => any | void |

Resize.handleResize(entries)

observer 回调;仅在 entries 包含当前元素时通知 listeners

| 参数 | 参数类型 | 返回值 | | --- | --- | --- | | entries | ResizeObserverEntry[] | void |

Resize.el

当前监听元素

| 类型 | | --- | | HTMLElement |

Resize.listeners

当前元素在默认模式下的监听函数;同一元素创建的实例会复用该数组

| 类型 | 类型 | | --- | --- | | Function[] | [] |

Resize.ro

默认模式下首次监听后创建的 observer

| 类型 | 类型 | | --- | --- | | ResizeObserver \| null | null |

回调仅在 observer entries 包含目标元素时执行。环境没有 ResizeObserver 时,on() 返回空解绑函数,不会抛错。

切换目标宽度,观察实例方法和静态方法共享同一元素监听状态:

:::playground

<script setup>
/* eslint-disable no-useless-assignment */
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
import { Resize } from '@deot/helper-resize';

const box = ref(null);
const width = ref(180);
const output = ref({ instanceCount: 0, staticCount: 0, width: 180 });
let offInstance = () => {};
let staticListener = () => {};

const toggle = async () => {
	width.value = width.value === 180 ? 300 : 180;
	await nextTick();
};

onMounted(() => {
	const instance = Resize.of(box.value);
	offInstance = instance.on(() => {
		output.value = { ...output.value, instanceCount: output.value.instanceCount + 1, width: box.value.offsetWidth };
	});
	staticListener = () => {
		output.value = { ...output.value, staticCount: output.value.staticCount + 1, width: box.value.offsetWidth };
	};
	Resize.on(box.value, staticListener);
});

onBeforeUnmount(() => {
	offInstance();
	Resize.off(box.value, staticListener);
});
</script>

<template>
	<div class="demo">
		<button @click="toggle">切换宽度</button>
		<div ref="box" class="box" :style="{ width: `${width}px` }">{{ width }}px</div>
		<strong>输出</strong>
		<pre>{{ JSON.stringify(output, null, 2) }}</pre>
	</div>
</template>

<style>
.demo { display: grid; width: min(100%, 640px); gap: 12px; padding: 12px; box-sizing: border-box; font: 14px/1.5 sans-serif; }
button { width: fit-content; padding: 6px 10px; cursor: pointer; border: 1px solid #cbd5e1; border-radius: 8px; background: #fff; }
.box {
	max-width: 100%;
	padding: 18px;
	color: #1d4ed8;
	background: #dbeafe;
	border-radius: 8px;
	box-sizing: border-box;
	transition: width 180ms ease;
}
pre { margin: 0; padding: 12px; border-radius: 8px; background: #f8fafc; }
</style>

:::