简单写个图片预览

92 阅读2分钟

20250312100315_rec_-convert.gif

掘金上面的图片预览 其中的transition 是复制过来的 transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) !important; 效果和下面2张图片差不多

aaa.jpg

img2.jpg

思路

  1. 准备一个imgA,作动画效果(<img class="theP hiddenP">)
  2. 点击原本图片是,计算scale,以及设计left top居中,
  3. 遮罩层顶层放一个div,用于监听事件(点击,滑动)
  4. 点击/滑动时,imgA复位,然后display:none

html

  <body style="margin: 0">
    <div id="box" style="height: 100vh; overflow: auto">
      <div style="height: 500px"></div>
      <span>图片1</span>
      <img class="topreview" src="./img/aaa.jpg" />
      <div style="height: 500px"></div>
      <span>图片2</span>
      <img class="topreview" src="./img/img2.jpg" />
      <div></div>
      <div style="height: 500px"></div>
      <img
        class="theP hiddenP"
        style="display: none"
        class="hiddenP"
        src="./img/1714029437897.jpg"
      />
      <div class="bgmask"></div>
      <div class="bgmask2"></div>
      <div style="height: 500px"></div>
      <div style="height: 500px"></div>
      <div style="height: 500px"></div>
      <div style="height: 500px"></div>
    </div>
  </body>

样式

<style>
      .theP {
        /* transition: 18s all; */
        transform-origin: top left;
        z-index: 100;
        position: fixed;
        transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) !important;
      }
      .bgmask {
        width: 100vw;
        height: 100vh;
        background: rgba(0, 0, 0, 0.7);
        opacity: 0.5;
        display: none;
        position: fixed;
        z-index: 10;
        top: 0;
        left: 0;
      }
      .bgmask2 {
        width: 100vw;
        height: 100vh;
        background: rgba(0, 0, 0, 0.7);
        opacity: 0;
        display: none;
        position: fixed;
        z-index: 200;
        top: 0;
        left: 0;
      }
    </style>

JS

    const imgs = document.querySelectorAll(".topreview"); // 页面中的所有图片
    const bigImg = document.querySelector(".hiddenP");// 预览图片
    const bgmask = document.querySelector(".bgmask");//遮罩层
    const bgmask2 = document.querySelector(".bgmask2");//遮罩层顶层 监听滑动事件和点击事件
    const prex = document.body.clientHeight / document.body.clientWidth; 
    let topPreImge = 0;// 用于记录点击前 图片的位置
  
    let current = null;
    for (const img of imgs) {
      img.onclick = function (e) {
        current = this;// 正在预览的图片
        const { left, top } = this.getBoundingClientRect();
        topPreImge = top;// 用于记录点击前 图片的位置
        const prexImg = this.clientHeight / this.clientWidth;
        let scale = 1;
        let trTop = "";
        let trLeft = "";
        if (prex < prexImg) {
          //高度先撑满
          scale = window.innerHeight / this.clientHeight;
          trTop = -(top / scale);
          const w = (window.innerWidth - scale * this.clientWidth) / 2;
          trLeft = (w - left) / scale;
        } else {
          scale = window.innerWidth / this.clientWidth;
          trLeft = -(left / scale);
          const h = (window.innerHeight - scale * this.clientHeight) / 2;
          trTop = (h - top) / scale;
        }

        //预览图片宽高不变
        bigImg.style = `display:block;left:${left};top:${top};
                            height:${this.clientHeight}px;
                            width:${this.clientWidth}px;`;

        bgmask.style = `display:block;`;
        bgmask2.style = `display:block;`;
        setTimeout(() => {
          bigImg.style = `left:${left}px;top:${top}px;display:block;
                            height:${this.clientHeight}px;
                            width:${this.clientWidth}px;
                            transform:scale(${scale}) translate3d(${trLeft}px, ${trTop}px, 0px);
                           `;
                            current.style.visibility='hidden'
        }, 100);//使用setTimeout transition不支持display:none
        bigImg.src = this.src;
      };
    }
    function clickBg() {
      const { left, top } = current.getBoundingClientRect();
      if (top == topPreImge) { // 位置不变
        bigImg.style.transform = "";
      } else { // 位置改变
        bigImg.style.transform = `translate3d(0px,${
          top - topPreImge // 复位
        }px,0px)`;
      }
      bgmask.style.display = "none"; // 隐藏
      bgmask2.style.display = "none"; // 隐藏
      setTimeout(() => {
        bigImg.style.display = "none"; // 使用setTimeout transition不支持display:none
         current.style.visibility='visible'
      }, 300);
    }
    bgmask2.onclick = clickBg;
    let t = null;
    bgmask2.onwheel = (e) => {
      let h = e.wheelDelta;
      if (h > 0) {
        //向上滑动
        box.scrollBy({
          top: -500,
          behavior: "smooth",
        });
      } else {
        // 向下滑动
        box.scrollBy({
          top: 500,
          behavior: "smooth",
        });
      }
      clearTimeout(t); // 防抖
      t = setTimeout(() => {
        clickBg();
      }, 300);
    };