妙妙屋方法实践

ResizeObserver

介绍

ResizeObserver 是一个 Web API,用于监听元素的大小变化。它可以观察一个或多个元素的尺寸改变,并在尺寸变化时触发回调函数。使用 ResizeObserver,您可以监测元素的宽度、高度或者它们的任意变化,而不需要轮询或使用其他复杂的解决方案。

案例

比如在开发h5的时候需要对屏幕是横屏还是竖屏进行监听

js 复制代码
const target = document.querySelector('body');
const observer = new ResizeObserver(entries => {
  for (let entry of entries) {
    const { width, height } = entry.contentRect;

    if (width < height) {
      // 屏幕从横屏变为竖屏
      // 执行逻辑处理
    } else {
      // 屏幕从竖屏变为横屏
      // 执行逻辑处理
    }
  }
});
// 启动观察
observer.observe(target);
// 停止观察 
observer.unobserve(target);

getBoundingClientRect

介绍

getBoundingClientRect 是一个 DOM API,用于获取元素的大小和位置信息。它返回一个 DOMRect 对象,包含了元素的位置、宽度、高度和其他相关属性。

示例

比如图片懒加载的原理

js 复制代码
 window.addEventListener('scroll', () => {
      const lazyImages = document.querySelectorAll('.lazy-image');

      for (let i = 0; i < lazyImages.length; i++) {
        const image = lazyImages[i];

        if (isInViewport(image)) {
          image.src = image.dataset.src;
          image.classList.remove('lazy-image');
        }
      }
    });

    function isInViewport(element) {
      const rect = element.getBoundingClientRect();

      return (
        rect.top < (window.innerHeight || documentElement.clientHeight)
      );
    }

IntersectionObserver

介绍

IntersectionObserver是一个JavaScript API,用于异步检测目标元素与其祖先或视窗之间的交叉状态。它提供了一种有效的方法来监听元素是否进入或离开视窗,或者与其祖先元素相交的程度。这对于实现懒加载、无限滚动、元素可见性等功能非常有用。

示例

实现一个简单的传送门的效果,类似于vue3的Teleport,在我们看b站视频的时候,下拉看评论的时候,会看到右下角会出现一个小的弹窗同步我们看视频的效果。

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Video Portal</title>
  <style>
    #video {
      width: 250px;
      height: auto;
    }

    #portal {
      display: none;
      position: fixed;
      bottom: 20px;
      right: 20px;
      width: 250px;
      height: auto;
      background-color: rgba(0, 0, 0, 0.7);
      color: #fff;
      padding: 20px;
      text-align: center;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <h1>Video Portal</h1>

  <div id="v-box">
    <video id="video" src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm" controls></video>
  </div>
  <div style="height: 1000px;width: 100%;"></div>
  <div id="portal"></div>

  <script>
    // 创建 IntersectionObserver 实例
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          hidePortal();
        } else {
          showPortal();
        }
      });
    });

    // 获取视频元素和传送门元素
    const video = document.getElementById('video');
    const portal = document.getElementById('portal');
    const vBox = document.getElementById('v-box');

    document.addEventListener('scroll', function () {
      // 观察视频元素
      observer.observe(vBox);
    })
    // 停止观察
    // observer.unobserve(vBox)

    // 显示传送门
    function showPortal() {
      portal.appendChild(video)
      portal.style.display = 'block'
    }

    // 隐藏传送门
    function hidePortal() {
      vBox.appendChild(video)
      portal.style.display = 'none'
    }

  </script>
</body>

</html>

requestAnimationFrame

介绍

requestAnimationFrame是一个用于优化动画和渲染性能的JavaScript方法。它是浏览器提供的一个API,用于在下一次浏览器重绘之前调用指定的回调函数。

使用requestAnimationFrame来执行动画和其他需要频繁更新的操作比使用传统的setTimeoutsetInterval方法更有效,原因如下:

  1. requestAnimationFrame会在浏览器准备好进行重绘时触发回调函数,通常是每秒60次,以匹配大多数显示器的刷新频率。这样可以避免在不必要的时候进行重绘,提高性能和电池寿命。
  2. 当页面处于非激活状态时,requestAnimationFrame会暂停,避免不必要的计算和功耗。

示例

实现一个可以暂停和继续加载的进度条动画,通过切换浏览器的窗口可以发现进度条会暂停,切换回去之后又重新加载,非常的智能。

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <title>Loading Progress Bar Example</title>
  <style>
    .progress-bar-container {
      width: 100%;
      height: 20px;
      background-color: #ddd;
    }

    .progress-bar {
      height: 100%;
      background-color: #007bff;
      width: 0;
      transition: width 0.5s;
    }

    #start-button {
      margin-top: 10px;
    }
  </style>
</head>
<body>
  <div class="progress-bar-container">
    <div class="progress-bar"></div>
  </div>
  当前进度:<span id="number"></span>
  <button id="start-button">开始加载</button>
  <button id="stop-button">暂停</button>

  <script>
    const startButton = document.getElementById('start-button');
    const progressBar = document.querySelector('.progress-bar');
    const progressNum = document.getElementById('number');
    const stopButton = document.getElementById('stop-button');
    let tag = true
    let width = 0;

    startButton.addEventListener('click', () => {
      function animate() {
        if ( tag && width < 100) {
          width++;
          progressBar.style.width = width + '%';
          progressNum.innerHTML = width + '%';

          requestAnimationFrame(animate);
        }
      }

      animate();
    });

    stopButton.addEventListener('click', () => {
      if(tag){
        tag = false
        stopButton.innerHTML = '暂停'
      } else {
        tag = true
        stopButton.innerHTML = '继续';
        startButton.click();
      }
    })

  </script>
</body>
</html>

总结

上面这些方法我只是浅尝辄止的说明了下,但是无论是日常开发还是性能优化都十分有用,不仅仅是了解,我们应该更多的实践让我们的开发方式更加灵活,做到有的放矢,优雅的开发起来。

相关推荐
美酒没故事°22 分钟前
纯css实现蜂窝效果
前端·javascript·css
GISer_Jing44 分钟前
React useState 的同步/异步行为及设计原理解析
前端·javascript·react.js
mini榴莲炸弹1 小时前
什么是SparkONYarn模式?
前端·javascript·ajax
能来帮帮蒟蒻吗1 小时前
VUE3 -综合实践(Mock+Axios+ElementPlus)
前端·javascript·vue.js·笔记·学习·ajax·typescript
酷爱码1 小时前
HTML5中的Microdata与历史记录管理详解
前端·html
开开心心就好1 小时前
高效全能PDF工具,支持OCR识别
java·前端·python·pdf·ocr·maven·jetty
啊啊啊~~1 小时前
歌词滚动效果
javascript·html
球球和皮皮2 小时前
Babylon.js学习之路《四、Babylon.js 中的相机(Camera)与视角控制》
javascript·3d·前端框架·babylon.js
郭尘帅6663 小时前
vue3基础学习(上) [简单标签] (vscode)
前端·vue.js·学习
njsgcs3 小时前
opencascade.js stp vite webpack 调试笔记
开发语言·前端·javascript