小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
如题,第一反应:
window.addEventListener("resize", handler, useCapture)
简单粗暴,但缺点也明显:文档视图调整大小时会触发 resize 事件,针对的 仅是window,而普通的DOM元素没有 onresize 事件的。
所以,对普通的DOM元素进行尺寸大小变化的监听,抛弃错误的第一感觉,可选择以下方法:
ResizeObserver
ResizeObserver属于Web API
可以监听到
Element的内容区域或SVGElement的边界框改变 —— MDN ResizeObserver
通过构造器函数,new ResizeObserver(callback),创建并返回一个ResizeObserver对象,接着:
进行观察
ResizeObserver.observe(target, options)
-
开始观察指定dom
-
支持设置观察者将以哪种盒子模型来观察:指定options参数的box属性,可选值有content-box (默认值),border-box,和 device-pixel-content-box。传送门
结束观察
ResizeObserver.disconnect()
- 取消和结束所有目标dom的观察
ResizeObserver.unobserve(target)
- 取消和结束指定dom的观察
示例
<script>
export default {
methods: {
handleResize() {
console.log("handle resize");
}
},
mounted() {
const dom = this.$refs.target.$el; // 假设this.$refs.target返回是VueComponent对象
this.observer = new ResizeObserver(this.handleResize);
this.observer.observe(dom, { box: "border-box" });
},
beforeDestroy() {
this.observer.disconnect();
}
};
</script>
什么时候触发执行callback的?
- 初始化执行一次
- 文档视窗改变大小会执行
- 元素发现尺寸改变(非2导致)会执行
resize-observer-polyfill
ResizeObserver存在一定的浏览器兼容问题,详见 can i use
该npm包的定位是:
A polyfill for the Resize Observer API.
基于MutationObserve或Mutation Events实现:为了解决ResizeObserver API的浏览器兼容问题
(请注意:在 IE10 及更低版本中存在样式问题)
示例
Element UI的走马灯和隐藏组件:滚动条
// https://github.com/ElemeFE/element/blob/dev/src/utils/resize-event.js
import ResizeObserver from 'resize-observer-polyfill';
import { debounce } from 'throttle-debounce';
export const addResizeListener = function(element, fn) {
if (isServer) return;
if (!element.__resizeListeners__) {
element.__resizeListeners__ = [];
element.__ro__ = new ResizeObserver(debounce(16, resizeHandler));
element.__ro__.observe(element);
}
element.__resizeListeners__.push(fn);
};
// https://github.com/ElemeFE/element/blob/dev/packages/scrollbar/src/main.js
import { addResizeListener, removeResizeListener } from "@/utils/resize-event";
mounted() {
!this.noresize && addResizeListener(this.$refs.resize, this.update);
}
element-resize-detector
同resize-observer-polyfill,也是可监测DOM元素大小变化的npm包
定位是:
Optimized cross-browser resize listener for elements.
性能有所提升,用法类似ResizeObserver API
开始监听
listenTo(element, listener) 或 listenTo(options, element, listener)
结束监听
removeListener(element, listener) 或 removeAllListeners(element) 或 uninstall(element)
示例
<script>
import elementResizeDetectorMaker from "element-resize-detector";
export default {
methods: {
handleResize() {
console.log("do resize");
}
},
mounted() {
// Must be a DOM element or a collection of DOM elements.
const dom = this.$refs.col.$el;
this.observer = elementResizeDetectorMaker();
this.observer.listenTo(
{ strategy: "scroll" }, // 基于滚动的情况下,提高性能
dom,
this.handleResize
);
},
beforeDestroy() {
const dom = this.$refs.col.$el;
this.observer.removeListener(dom, this.handleResize);
}
};
</script>
vue-resize-observer
如上所述的3种方法,或多或少都需要记忆一些语法
Q:Vue中,为什么不可以是一个自定义指令呢?
A:主角往往在最后出现,使用 vue-resize-observer 即可
注意:已支持Vue 3.x
示例
安装,在入口文件中引用:
import VueResizeObserver from "vue-resize-observer";
Vue.use(VueResizeObserver);
<div class="demo" v-resize="handleResize"></div>
export default {
methods: {
handleResize(info) {
console.log("do resize", info); // info输出:对象,元素当前width、height
}
}
};
</script>
什么时候触发执行handleResize?
- 初始化不会执行一次
- 文档视窗改变大小会执行
- 元素发现尺寸改变(非2导致)会执行
链接传送门
Last but not least
如有不妥,请多指教呀~