前端开发攻略---Vue通过自定义指令实现元素平滑上升的动画效果(可以自定义动画时间、动画效果、动画速度等等)。

1、演示

2、介绍

这个指令不是原生自带的,需要手动去书写,但是这辈子只需要编写这一次就好了,后边可以反复利用。

3、关键API

IntersectionObserver

IntersectionObserver 是一个用于监测元素是否进入或离开视口(viewport)的 API。它可以帮助你在页面滚动时或者元素位置改变时进行回调操作,这样你就可以根据元素是否可见来触发动作或者动画效果。

使用 IntersectionObserver 的基本步骤如下:

  1. 创建一个 IntersectionObserver 对象,并指定一个回调函数。这个回调函数会在被观察的元素进入或离开视口时被调用。

  2. 使用 observe() 方法开始观察指定的元素。你可以同时观察多个元素。

  3. 在回调函数中处理元素的可见状态变化。根据元素的可见性状态来执行相应的操作,比如触发动画、加载内容等。

  4. 在不需要观察元素时,使用 unobserve() 方法停止观察。

以下是一个简单的示例代码,演示了如何使用 IntersectionObserver 来监测元素的可见性:

javascript 复制代码
// 创建一个 IntersectionObserver 对象
const observer = new IntersectionObserver((entries) => {
  // 遍历观察到的所有元素
  entries.forEach(entry => {
    // 如果当前元素进入视口
    if (entry.isIntersecting) {
      // 执行相应的操作,比如触发动画
      entry.target.classList.add('animate');
      // 停止观察当前元素,可根据需求决定是否停止观察
      observer.unobserve(entry.target);
    }
  });
});

// 要观察的目标元素
const targetElement = document.querySelector('.target');

// 开始观察目标元素
observer.observe(targetElement);

4、Vue文件代码

html 复制代码
<template>
  <div class="container">
    <div v-slide-in class="item" v-for="item in 10">{{ item }}</div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
</script>

<style scoped lang="scss">
.container {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.item {
  width: 50%;
  height: 200px;
  margin-bottom: 20px;
  text-align: center;
  line-height: 200px;
  font-size: 50px;
  color: #fff;
  box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 10px 0px;
}
.item:nth-child(1) {
  background-color: rgb(87, 139, 19);
}
.item:nth-child(2) {
  background-color: rgb(33, 139, 19);
}
.item:nth-child(3) {
  background-color: rgb(139, 19, 35);
}
.item:nth-child(4) {
  background-color: rgb(139, 19, 87);
}
.item:nth-child(5) {
  background-color: rgb(139, 19, 135);
}
.item:nth-child(6) {
  background-color: rgb(91, 19, 139);
}
.item:nth-child(7) {
  background-color: rgb(19, 133, 139);
}
.item:nth-child(8) {
  background-color: rgb(221, 218, 40);
}
.item:nth-child(9) {
  background-color: rgb(173, 139, 115);
}
.item:nth-child(10) {
  background-color: rgb(29, 28, 27);
}
</style>

5、指令文件及代码注释(清晰明了)

javascript 复制代码
// WeakMap是一种键值对的集合
// 这里用来将一个dom元素和一种动画对应起来
const map = new WeakMap()

// 创建一个观察对象
const ob = new IntersectionObserver(entries => {
  // 遍历所有被观察的元素 entries为一个数组
  for (const entry of entries) {
    // 判断该元素是否与视口相交(出现在视口里面了)
    if (entry.isIntersecting) {
      // 判断目标元素是出现在上视口还是下视口
      if (entry.boundingClientRect.top > entry.rootBounds.top) {
        // 找出这个元素对应的动画
        const animation = map.get(entry.target)
        if (animation) {
          // 播放该元素的动画
          animation.play()
        }
      }
    }
  }
})
// 辅助函数,用来判断页面上的元素是否在视口外
function isBelowViewport(el) {
  const rect = el.getBoundingClientRect()
  return rect.top > window.innerHeight
}

export default function (app) {
  app.directive('slideIn', {
    mounted(el, bindings) {
      // 如果元素已经在视口内了,直接return 不加动画
      if (!isBelowViewport(el)) return
      //  创建一个动画  animate是Vue自带的
      const animation = el.animate(
        [
          // 数组的每一个对象都表示关键帧 相当于css中的 @keyframes 这里想写多少个就写多少个
          {
            transform: `translateY(${200}px)`,
          },
          {
            transform: `translateY(0px)`,
          },
        ],
        // duration:执行时间  easing:动画效果,fill:动画结束过后的行为  这些跟css中的一样
        { duration: 1000, easing: 'ease-in-out', fill: 'forwards' }
      )
      // 一开始的时候让动画暂停,这里只是先定义好
      animation.pause()
      // 当元素进入视口的时候在进行动画播放
      ob.observe(el)
      // 存储键值
      map.set(el, animation)
    },
    // 在元素卸载时,取消观察
    unmounted(el) {
      ob.unobserve(el)
    },
  })
}
相关推荐
lpfasd1235 小时前
node-sass 停止维护!老项目迁移 Dart Sass 完整教程
前端·rust·sass
Data analyse4568 小时前
rnweb 回放数据量太大怎么办?分片存储与断点续传的实现思路
前端·网络·算法·数据分析
xiaogai_gai8 小时前
金蝶收料通知单查询策略实战教程:从源系统拉取到中间层落地的完整路径
java·前端·数据库
环境栈笔记9 小时前
指纹浏览器 WebRTC 怎么设置?从 ICE 候选、代理出口到功能验证
前端·人工智能·后端·自动化
赵大仁9 小时前
官网性能优化实战:LCP 3.2s → 2.1s、CLS 0.107 → 0,以及被我推翻的 6 个判断
前端·性能优化·cls·lcp·core web vitals
xiancai_xianyu9 小时前
Text2SQL落地生产库前,SQL要过哪三道闸
前端·数据库·sql·sql注入·text2sql·ai agent开发·企业级ai框架
小羊没烦恼!9 小时前
T-SQL查询进阶--理解SQL SERVER中的分区表
服务器·开发语言·前端·javascript·html
史瓦辛格10 小时前
给 DeepSeek Harness 写费用插件:把「这次会话花了多少钱」算准
前端·deepseek
星光不问赶路人10 小时前
Vue 3 + TypeScript 中 enum 的使用实践
前端·vue.js
鸥梨菌Honevid10 小时前
UVM 中 REQ 和 RSP 类型详解:从通信模型到 item_done 与 put_response
java·前端·servlet