React实现窗口自适应、自适应防抖、memo 缓存优化、监听元素尺寸变化

目录

窗口自适应

过渡动画

监听宽高:window.listener.resize

防抖优化:lodash-es/debounce

*forwardRef暴露结点给父组件(ref)

Echart实例,可直接调用实例的原生函数

React.memo缓存优化:避免重新渲染

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 事件或 MutationObserverResizeObserver 只关注被观察元素的尺寸变化,避免了不必要的计算和触发,提供了更优化的性能。
  • 同时观察多个元素
    ResizeObserver 允许一次性观察多个元素的尺寸变化。通过将多个目标元素传递给 observe 方法,可以同时监听它们的尺寸变化,而不需要为每个元素单独创建监听器。
  • 提供准确的尺寸信息
    在回调函数中,ResizeObserver 提供了准确的尺寸信息。这包括目标元素的宽度、高度、上下左右边界的偏移量等,使开发者可以根据需要进行动态布局或样式调整。
  • 触发方式灵活可控
    ResizeObserver 的触发方式灵活可控。它可以通过设置不同的触发选项来决定在什么情况下触发回调函数,例如只在尺寸变化结束后触发、只在尺寸增加或减少时触发等。
  • 兼容性和浏览器支持
    ResizeObserverW3C 规范定义的标准 API,得到了现代浏览器的支持,包括 ChromeFirefoxSafariEdge 等。尽管在一些旧版本的浏览器中不被支持,但可以使用 polyfill 或第三方库来提供兼容性支持。
  • 动态响应式布局
    由于 ResizeObserver 可以精确监听元素的尺寸变化,它在实现动态响应式布局时非常有用。开发者可以根据元素尺寸的变化,实时调整布局或重新计算样式,从而实现更好的用户体验。 ResizeObserver 的出现填补了在原生 JavaScript 中监听元素尺寸变化的空白,为开发者提供了更好的解决方案,使得元素尺寸变化的检测更加准确、高效,从而改善了响应式布局的开发体验

参考链接:React hooks 封装 ECharts5 通用组件 - 掘金

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值