Vue3实现 元素进入可视范围内执行动画的效果

HTML部分(为了效果整得有点多)

思路:

  • 为每个元素绑定 ref 和 :class,
  • 初始化一个 visibleItems 数组,值为布尔值
  • 通过setBoxRef来获取dom元素,
  • 使用 IntersectionObserver 检测每个元素是否进入视口,并在进入视口时设置 visibleItems 的值为 true
  • 定义 visible 类和关键帧动画 @keyframes 来实现元素的进入动画。
<template>
  <div class="container">
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[0] }"
      style="opacity: 0"
    >
      <h4>字体</h4>
      <div class="lbt_content scontent">1</div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[1] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[2] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[3] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[4] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent">123</div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[5] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent">1231</div>
    </div>
  </div>
</template>

<template>
  <div class="container">
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[0] }"
      style="opacity: 0"
    >
      <h4>字体</h4>
      <div class="lbt_content scontent">1</div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[1] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[2] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[3] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[4] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent">123</div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[5] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent">1231</div>
    </div>
  </div>
</template>

<template>
  <div class="container">
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[0] }"
      style="opacity: 0"
    >
      <h4>字体</h4>
      <div class="lbt_content scontent">1</div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[1] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[2] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[3] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent"></div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[4] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent">123</div>
    </div>
    <div
      class="lbt content"
      :ref="setBoxRef"
      :class="{ visible: visibleItems[5] }"
      style="opacity: 0"
    >
      <h4>轮播图</h4>
      <div class="lbt_content scontent">1231</div>
    </div>
  </div>
</template>

TypeScript部分​​

<script setup lang="ts">
import { onMounted, ref, reactive } from "vue";
const visibleItems = reactive([]);
/* 保存观察dom元素 */
const boxrefList = reactive([]);
/* 获取要观察的dom元素 */
const setBoxRef = (el: any) => {
  if (el) {
    boxrefList.push(el);
  }
};
const observeElements = () => {
  const options: any = {
    root: null, // 视口为浏览器窗口
    rootMargin: "0px",
    threshold: 0, // 当元素 0% 可见时触发
  };

  const observer = new IntersectionObserver((entries) => {
    /*
     *遍历IntersectionObserverEntry对象
     *每个 IntersectionObserverEntry 对象包含有关目标元素与视口或其祖先元素的交叉状态的信息
     */
    entries.forEach((entry) => {
      /* 查找entry.target在boxrefList中的索引 */
      const index = Array.from(boxrefList).indexOf(entry.target);
      /* entry.isIntersecting 为一个布尔值,表示目标元素是否与视口或其祖先元素相交 */

      if (entry.isIntersecting) {
        /* 如果 entry.isIntersecting 为 true,则将 visibleItems 对应索引位置的值设为 true,表示该元素在视口中 */
        visibleItems[index] = true;
      } else {
        /* 如果 entry.isIntersecting 为 false,则将 visibleItems 对应索引位置的值设为 false,表示该元素不在视口中 */
        visibleItems[index] = false;
      }
    });
  }, options);
  /* 遍历需要观察的元素,然后通过observer 来观察box元素 */
  boxrefList.forEach((box) => {
    observer.observe(box);
  });
};
onMounted(() => {
  observeElements();
});
</script>

css部分

.container {
.content {
width: 100%;
margin-bottom: 50px;
background: white;
box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.3);
padding: 10px;
box-sizing: border-box;
border-radius: 20px;

.scontent {
  height: 700px;
}

}
.visible {
opacity: 1;
transform-origin: bottom center;
animation: enter-animation 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
/* 动画 */
@keyframes enter-animation {
0% {
transform: scale(0.95) translateY(40px);
opacity: 0;
}

100% {
  transform: scale(1) translateY(0);
  opacity: 1;
}

}
}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!