• React魔法堂:sizesensor源码略读


    前言

    echarts-for-react在对echarts进行轻量级封装的基础上,额外提供图表尺寸自适应容器尺寸的这小而实用的功能,而这功能的背后就是本文想介绍的size-sensor了。

    源码介绍

    size-sensor源码十分精简,主要是对原生APIResizeObserver方案和object元素方案进行检测和API统一化而已。

    代码首先会检测当前运行时是否支持原生APIResizeObserver,若不支持则使用object元素方案。下面我们将对两种方案进行探讨。

    基于浏览器原生API - ResizeObserver实现

    用于监听Element内容盒子或边框盒子或者SVGElement边界尺寸的大小,并调用回调函数。
    MDN: https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver

    /**
     * @param {ResizeObserverEntry} entries - 用于获取每个元素改变后的新尺寸
     * @param {ResizeObserver} observer
     * @see https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserverEntry
     */ 
    function handleResize(entries, observer) {
      for (let entry of entries) {
        //......
      }
    }
    const target = document.getElementById('main')
    
    const observer = new ResizeObserver(handleResize)
    
    // 开始对指定DOM元素的监听
    observer.observe(target)
    
    // 结束对指定DOM元素的监听
    observer.unobserve(target)
    
    // 结束对所有DOM元素的监听
    observer.disconnect()
    

    注意:在handleResize中修改target的尺寸并不会导致递归调用handleResize函数。

    基于object元素的兼容方案实现

    object元素用于内嵌图像、音频、视频、Java applets、ActiveX、PDF和Flash等外部资源,因此其也会像iframe元素那样生成独立的browser context。
    而browser context中Window实例的尺寸会保持和object元素的一致,因此可以通过订阅browser context中Window实例的resize事件实现对容器的尺寸的监听。

    function bind(target, handle) {
      if (getComputedStyle(target).position === 'static') {
        target.style.position = 'relative'
      }
    
      let object = document.createElement('object')
      object.onload = () => {
        object.contentDocument.defaultView.addEventListener('resize', handle)
        // 初始化时先触发一次
        handle()
      }
      object.style.display = 'block'
      object.style.position = 'absolute'
      object.style.top = 0
      object.style.let = 0
      object.style.width = '100%'
      object.style.height = '100%'
      object.style.pointerEvents = 'none'
      object.style.zIndex = -1
      object.style.opacity = 0
      object.type = 'text/html'
    
      target.appendChild(object)
      object.data = 'about:data'
    
      return () => {
        if (object.contentDocument) {
          object.contentDocument.defaultView.removeEventListener('resize', handle)
        }
        if (object.parentNode) {
          object.parentNode.removeChild(object)
        }
      }
    }
    

    这里将object元素替换为iframe元素也是可以的,只需将object.data换成iframe.src即可。
    注意:在handle中修改target的尺寸并会导致递归调用handle函数。

    ResizeObserver的polyfill兼容方案 - MutationObserver

    Repos: https://github.com/que-etc/resize-observer-polyfill
    Repos: https://github.com/juggle/resize-observer

    尊重原创,转载请注明来自:https://www.cnblogs.com/fsjohnhuang/p/16814327.html 肥仔John

  • 相关阅读:
    商人的诀窍 结构体
    商人的诀窍 结构体
    小泉的难题 结构体
    小泉的难题 结构体
    来淄博旅游 结构体
    来淄博旅游 结构体
    分类游戏 结构体
    7月20日学习
    7月19日学习
    7月18日学习
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/16814327.html
Copyright © 2020-2023  润新知