0
点赞
收藏
分享

微信扫一扫

「IDE」三大编译器GCC、Clang、MSVC说明

0 滚动动画?

一些好看的页面滚动动画实现,都是根据当前滚动的位置,逐渐“播放”动画。并不是随着时间播放,是随着滚动条向下滚动而播放。
一般都会有多个动画,每个动画在某一个滚动区间内进行播放,超过区间后隐藏或者是滚动出当前视窗(利用sticky定位)。
于是就需要监听元素滚动的位置,实时计算当前动画的进度。

1 技术实现

为滚动父元素添加滚动事件监听,实时计算每一个动画的进度(可以映射到透明度、大小、位置等的变化)。每一个动画可以包含这样一些属性:

{
	startY:开始动画的坐标
	endY:结束动画的坐标
	startVal:动画进度起始值
	endVal:动画进度结束值
	currVal/updateCurrVal:当前动画进度值/当前动画更新函数
}

当父元素滚动时,可以去循环这样一个动画列表,逐个计算当前动画进度,并通过他自身的属性更新对应的动画进度。


结合Vue3 特性

利用Vue3的响应式以及自定义指令:将动画对象的当前进度值设置为一个响应式数据,滚动的时候直接更新其值可以同步更新视图;通过自定义指令作用于滚动父元素,将动画对象列表传入,通过指令绑定滚动、更新每一个动画值。同时,自定义指令的方式,可以实现多场景复用。

demo.vue

<script setup lang="ts">
import { ref } from "vue";
import {vScrollIndex} from '../your/path/scrollIndex'

const anm0 = ref(0)
const anm1 = ref(0)
const anm2 = ref(1)
const anm3 = ref(0)

const options = [
  {startY: 10, endY: 400, startVal: 0, endVal: 1, bind: anm0},
  {startY: 500, endY: 800, startVal: -10, endVal: 16, bind: anm1},
  {startY: 900, endY: 1300, startVal: 1, endVal: 10, bind: anm2},
  {startY: 1400, endY: 1600, startVal: 20, endVal: 60, bind: anm3}
]
</script>

<template>
  <main>
    <div class="show" title="动画值更新展示区">
      <div class="item">
        0: {{ anm0 }}
      </div>
      <div class="item">
        1: {{ anm1 }}
      </div>
      <div class="item">
        2: {{ anm2 }}
      </div>
      <div class="item">
        3: {{ anm3 }}
      </div>
    </div>
    <div class="wrap" v-scroll-index="{options}" title="滚动父元素">
      <div class="item" v-for="idx in 40" :key="idx">
        {{ String.fromCharCode(30 + idx).repeat(30) }}
      </div>
    </div>
  </main>
</template>

<style lang="scss">
.wrap {
  height: 800px;
  overflow-y: scroll;
  .item{
    margin: 20px;
  }
}
</style>

vScrollIndex.ts

import type { Directive, DirectiveBinding, Ref } from "vue";
interface IOption{
  startY: number
  endY: number
  startVal: number
  endVal: number
  bind: Ref<number>
}
export interface ScrollIndexBinding{
  options: Array<IOption>
  [key: string | number]: any
}
let updateAll
function handleScroll(options: IOption[]){
  function updateArr(event: Event){
    const scrollTop = (event.target as HTMLElement).scrollTop;
    options.forEach(item => {
      const { startY, endY, startVal, endVal, bind } = item;
      if(scrollTop <= startY){
        bind.value = startVal
      }else if(scrollTop >= endY){
        bind.value = endVal
      }else{
        bind.value = (scrollTop - startY) / (endY - startY) * (endVal - startVal);
      }
    })
  }
  return updateArr
}
export const vScrollIndex: Directive = {
  mounted: (el:Element, binding: DirectiveBinding<ScrollIndexBinding>) => {
    const { options } = binding.value;
    updateAll = handleScroll(options)
    el.addEventListener('scroll', updateAll)
  },
  unmounted: (el) => {
    el.removeEventListener('scroll', updateAll!)
  }
}

2 效果展示

在这里插入图片描述

举报

相关推荐

0 条评论