Skip to content

观察者实现滚动动画

演示

向下滚动查看效果
<template>
  <div class="container">
    <div class="full">
      向下滚动查看效果
    </div>
    <div class="box-container" ref="boxContainer">
      <div v-for="item in list" :key="item.id" class="box hide" :style="item.style">
      </div>
    </div>
  </div>
</template>

<script setup lang='ts'>
import { ref, onMounted } from 'vue';
defineOptions({
  name: 'observer',
});

// 生成随机颜色
const randomColor = () => {
  const chars = "1234567890abcdef",
    colorLength = 6;

  let color = '#';
  for (let i = 0; i < colorLength; i++) {
    const p = Math.floor(Math.random() * chars.length);
    color += chars.substring(p, p + 1);
  };

  return color;
};

//  生成列表数据
const list = Array.from({ length: 60 }, (v, i) => i).map((v) => ({
  id: v,
  style: {
    backgroundColor: randomColor(),
    'border-radius': '5px',
    width: '80px',
    height: '80px',
    'margin-bottom': '10px',
  },
}));

// 盒子容器
const boxContainer = ref<HTMLElement | null>(null);

onMounted(() => {
  if (boxContainer.value) {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        const dom = entry.target as HTMLElement;
        const isIntersecting = entry.isIntersecting
        dom.classList.add(isIntersecting ? 'show' : 'hide');
        dom.classList.remove(isIntersecting ? 'hide' : 'show');
        if (isIntersecting) observer.unobserve(dom)
      });
    }, {
      threshold: 0.1,
    });

    const boxs = boxContainer.value.querySelectorAll('.box-container > div');
    boxs.forEach((box) => {
      observer.observe(box);
    });
  }
})
</script>

<style lang='scss' scoped>
.container {
  justify-content: space-between;
  width: 100%;
  min-width: 300px;
  height: 400px;
  overflow: auto;
  background-color: rgba($color: #000000, $alpha: 1);

  .full {
    width: 100%;
    height: 400px;
    line-height: 400px;
    text-align: center;
    font-weight: 700;
    font-size: 20px;
    color: #fff;
  }

  .box-container {
    margin: 0 auto;
    justify-content: space-around;
    display: flex;
    flex-wrap: wrap;
    width: 300px;

    .box {
      transition: all 0.5s;
    }

    .box:nth-child(3n + 1) {
      transform: translate(-100px, 0) scale(0);
    }

    .box:nth-child(3n + 2) {
      transform: translate(0, 0px) scale(0);
    }

    .box:nth-child(3n + 3) {
      transform: translate(100px, 0) scale(0);
    }

    .box.show {
      opacity: 1;
      transform: translate(0, 0);
    }
  }
}
</style>