自定义元素出现的加载动画

创建 directives 文件,新建 vSlideIn.js 指令文件

/**
 * @Author : xlsir
 * @Description: vSlideIn
 * @Create_time: 2025-08-03 08:18
 */
const DISTANCE = 100
const DURATION = 500
const map = new WeakMap()

const ob = new IntersectionObserver(entries => {
    for (const entry of entries) {
        if (entry.isIntersecting) {
            //出现在视口
            const animation = map.get(entry.target)
            animation && animation.play()
            ob.unobserve(entry.target)
        }
    }
})

// 判断元素有没有在视口
function isBelowViewport(el) {
    const rect = el.getBoundingClientRect()
    return rect.top - window.innerWidth > 0
}

export default {
    mounted(el) {
        if (!isBelowViewport(el)) return
        const animation = el.animate([
            {
                transform: `translateY(${DISTANCE}px)`,
                opacity: 0.5,
            }, {
                transform: `translateY(0)`,
                opacity: 1,
            }], {
            duration: DURATION,
            easing: 'ease-out',
            fill: 'forwards'
        });
        animation.pause()
        map.set(el, animation)
        ob.observe(el)
    },
    unmounted(el) {
        ob.unobserve(el)
    }
}

如何使用

  1. main.js注册

    import { createApp } from 'vue'
    import App from './App.vue'
    import vSideIn from '@/directives/vSlideIn.js' //引入指令文件
    const app = createApp(App)
    
    app.directive('side-in',vSideIn)
    app.mount('#app')
  2. 文件使用

    <template>
      <div class="content">
     <div v-side-in  class="items" v-for="i in 20">{{i}}</div>
      </div>
    </template>
    <style scoped>
    .content{
      width: 900px;
      margin: 0 auto;
    }
    .items{
      width: 100%;
      aspect-ratio: 2/1;
      margin: 5vw 0;
      border-radius: 5px;
      box-shadow: 0 0 10px rgba(0,0,0,0.5);
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 10vw;
      color: #fff;
    }
    .items:nth-child(3n+1) {
      background-color: orange;
    }
    
    .items:nth-child(3n+2) {
      background-color: red;
    }
    
    .items:nth-child(3n+3) {
      background-color: green;
    }
    </style>
评论区
头像
文章目录