目录
hooks(useEffect, useRef)+ResizeObserver 监听元素尺寸变化
窗口自适应
过渡动画
// 窗口自适应并开启过渡动画
const resize = () => {
if(cInstance.current) {
cInstance.current.resize({
animation: { duration: 300 },
});
}
};
监听宽高:window.listener.resize
// 监听窗口大小
useEffect(() => {
//组件渲染后添加
window.addEventListener('resize', debounceResize);
//组件卸载后移除
return () => {
window.removeEventListener('resize', debounceResize);
};
}, []);
//手动修改
const EChart = (props) => {
const { style } = props;
// 监听高度变化
useLayoutEffect(() => {
resize();
}, [style.width, style.height]);
}
resize
事件触发也有些频繁,有一定的性能问题。
防抖优化:lodash-es/debounce
使用 debounceResize
替换 resize
import debounce from 'lodash-es/debounce';
// 自适应防抖优化
const debounceResize = debounce(resize, 500);
*forwardRef暴露结点给父组件(ref)
Echart实例,可直接调用实例的原生函数
对父组件暴露获取 ECharts 实例的方法,让父组件可直接通过实例调用原生函数。
const EChart = (props, ref) => {
// 略......
// 获取实例
const getInstance = () => cInstance.current;
// 暴露方法
useImperativeHandle(ref, () => ({ getInstance }));
}
export default React.forwardRef(EChart);
React.memo缓存优化:避免重新渲染
作为一个全局通用组件,在 props 不变的情况下,跳过重新渲染
export default React.memo(React.forwardRef(EChart));
hooks(useEffect, useRef)+ResizeObserver 监听元素尺寸变化
调整一个固定在顶部的占位符 div
的高度,以适应不同的屏幕和父元素尺寸
// 导入 React 的 useEffect 和 useRef 钩子,以及 ResizeObserver polyfill。
import { useEffect, useRef } from "react"
import ResizeObserver from 'resize-observer-polyfill'
// 定义 React 函数组件 FixTopPlaceHolder。
export default function FixTopPlaceHolder() {
// 使用 useRef 创建一个引用,指向 DOM 元素,这里是一个 div。
const holderRef = useRef<HTMLDivElement>(null)
// 使用 useEffect 钩子来执行副作用操作。
useEffect(() => {
// 通过 useRef 获取到的当前 holder 元素。
const holder = holderRef.current
// 如果 holder 元素不存在,直接返回。
if (!holder) return
// 获取 holder 元素的父元素。
const parent = holder.parentElement
// 如果父元素不存在,直接返回。
if (!parent) return
// 尝试获取父元素的父元素的父元素,这里假设是一个滚动容器。
const scroll = parent.parentElement?.parentElement
// 如果滚动容器不存在,直接返回。
if (!scroll) return
// 创建一个新的 ResizeObserver 实例来监听元素尺寸的变化。
const observer = new ResizeObserver(entries => {
// 只处理第一个观察到的元素的尺寸变化。
if (entries[0]) {
// 获取滚动容器的高度。
const scrollHeight = scroll.clientHeight
// 获取父元素的高度。
const parentHeight = parent.getBoundingClientRect().height
// 获取 holder 元素的高度。
const holderHeight = holder.clientHeight
// 检查是否需要调整 holder 的高度,这里的逻辑是确保 scrollHeight 大于父元素和 holder 元素高度之差。
if (scrollHeight > parentHeight - holderHeight) {
holder.style.height = Math.round(holderHeight + scrollHeight - parentHeight - 20) + 'px'
return
}
// 查找父元素中的特定子元素,假设其 ID 为 'lastLine'。
const target = parent.querySelector('#lastLine') as HTMLElement
if (!target) {
holder.style.height = '0px'
return
}
// 计算 target 元素顶部到父元素底部的距离。
const parentBottom = parent.getBoundingClientRect().bottom
const targetTop = target.getBoundingClientRect().top
const distanceToParentBottom = parentBottom - targetTop - holderHeight
// 根据计算的距离调整 holder 的高度,确保其不会覆盖 target 元素。
holder.style.height = Math.max(Math.round(scrollHeight - distanceToParentBottom - 20), 0) + 'px'
}
})
// 开始观察父元素的尺寸变化。
observer.observe(parent)
// 组件卸载时,停止观察。
return () => observer.unobserve(parent)
}, [])
// 组件返回一个 div,该 div 使用 ref 引用 holderRef。
return <div ref={holderRef} />
}
- 监听元素尺寸变化
ResizeObserver
主要用于监听指定元素的尺寸变化。它可以观察目标元素的宽度、高度、边界框等尺寸属性的变化,并在发生变化时触发回调函数。 - 高性能和效率
ResizeObserver
设计用于高性能和效率的尺寸变化检测。相对于传统的resize
事件或MutationObserver
,ResizeObserver
只关注被观察元素的尺寸变化,避免了不必要的计算和触发,提供了更优化的性能。 - 同时观察多个元素
ResizeObserver
允许一次性观察多个元素的尺寸变化。通过将多个目标元素传递给observe
方法,可以同时监听它们的尺寸变化,而不需要为每个元素单独创建监听器。 - 提供准确的尺寸信息
在回调函数中,ResizeObserver
提供了准确的尺寸信息。这包括目标元素的宽度、高度、上下左右边界的偏移量等,使开发者可以根据需要进行动态布局或样式调整。 - 触发方式灵活可控
ResizeObserver
的触发方式灵活可控。它可以通过设置不同的触发选项来决定在什么情况下触发回调函数,例如只在尺寸变化结束后触发、只在尺寸增加或减少时触发等。 - 兼容性和浏览器支持
ResizeObserver
是W3C
规范定义的标准API
,得到了现代浏览器的支持,包括Chrome
、Firefox
、Safari
、Edge
等。尽管在一些旧版本的浏览器中不被支持,但可以使用polyfill
或第三方库来提供兼容性支持。 - 动态响应式布局
由于ResizeObserver
可以精确监听元素的尺寸变化,它在实现动态响应式布局时非常有用。开发者可以根据元素尺寸的变化,实时调整布局或重新计算样式,从而实现更好的用户体验。ResizeObserver
的出现填补了在原生JavaScript
中监听元素尺寸变化的空白,为开发者提供了更好的解决方案,使得元素尺寸变化的检测更加准确、高效,从而改善了响应式布局的开发体验