v-antm

useAnimationList.ts

import { ref } from 'vue'

export interface Timedtask {
  time: number
  method: (...arg: any[]) => void
}

const binaryInsert = (arr: { key: number; time: number }[], value: number) => {
  let left = 0
  let right = arr.length - 1
  let item: { key: number; time: number } = { key: 0, time: 0 }
  while (left <= right) {
    const mid = Math.floor((left + right) / 2)
    if (arr[mid].time === value) {
      item = { key: mid, time: value }
      arr.splice(mid, 0, item) // 如果找到相同的值,插入在该位置
      return item
    } else if (arr[mid].time < value) {
      left = mid + 1 // 在右半部分继续查找
    } else {
      right = mid - 1 // 在左半部分继续查找
    }
  }
  item = { key: left, time: value }
  arr.splice(left, 0, item) // 如果未找到相同的值,插入在合适的位置
  return item
}

export const animationList = () => {
  const tiskNumArray: { key: number; time: number }[] = []
  const tiskArray = new Map<any, Timedtask>()
  let intervalIndex: number | null = null
  let timeNum = 0
  const implementMethod = (item: (typeof tiskNumArray)[0]) => {
    const method = tiskArray.get(item)?.method
    console.log('执行', item.time, tiskNumArray)

    method && method()
    tiskArray.delete(item)
    tiskNumArray.shift()
    if (tiskNumArray.length === 0) clearIntervalM()
  }
  const clearIntervalM = () => {
    timeNum = 0
    intervalIndex && clearInterval(intervalIndex)
    intervalIndex = null
  }
  const diffTimeValue = (timeNum: number) => {
    if (timeNum >= tiskNumArray[0].time) {
      implementMethod(tiskNumArray[0])
      tiskNumArray.length > 0 && diffTimeValue(timeNum)
    }
  }
  const initInterval = () => {
    if (intervalIndex === null) {
      diffTimeValue(timeNum)
      intervalIndex = setInterval(() => {
        timeNum += 100
        diffTimeValue(timeNum)
      }, 100)
    }
  }

  const setTimedtask = (time: number, method: (...arg: any[]) => void) => {
    let index = 0
    let value = { key: index, time }
    if (tiskNumArray.length === 0) tiskNumArray.push(value)
    else {
      value = binaryInsert(tiskNumArray, time)
    }
    tiskArray.set(value, { time, method })
    if (tiskNumArray.length !== 0) initInterval()
  }

  return {
    setTimedtask
  }
}

directives.ts

import { animationList } from './useAnimationList'

const { setTimedtask } = animationList()

function callback(entries: any) {
  for (let i of entries) {
    if (i.isIntersecting) {
      let img = i.target
      let trueSrc = img.getAttribute('data-src')
      img.setAttribute('src', trueSrc)
      observer?.unobserve(img)
    }
  }
}
let observer: IntersectionObserver | null = null
try {
  observer = new IntersectionObserver(callback)
} catch (error) {
  observer = null
}

export const LazyImg = {
  beforeMount(el: Element, binding: { value: boolean }) {
    if (!observer || binding.value === false) return
    let trueSrc = el.getAttribute('src')
    el.setAttribute('src', null as unknown as string)
    el.setAttribute('data-src', trueSrc as string)
    observer.observe(el)
  },
  beforeUnmount(el: Element) {
    observer?.unobserve(el)
  }
}
const antmBindingObjs: { [key: number]: antmType } = {}
function antmCallback(entries: any) {
  for (let i of entries) {
    if (i.isIntersecting) {
      antmObserver?.unobserve(i.target)
      const uuid: number = Number(i.target.getAttribute('antm-id'))
      if (antmBindingObjs[uuid].child_node === true) {
        const flag = typeof antmBindingObjs[uuid].time === 'number'
        i.target.childNodes.forEach((childNode: any, index: number) => {
          setTimedtask(
            flag
              ? (antmBindingObjs[uuid].time as number) * ++index
              : (antmBindingObjs[uuid].time as number[])[index],
            () => {
              childNode.classList.add(antmBindingObjs[uuid].after)
              if (antmBindingObjs[uuid].opacity) childNode.style.opacity = 1
            }
          )
        })
      } else
        setTimedtask((antmBindingObjs[uuid].time as number[])[0], () => {
          i.target.classList.add(antmBindingObjs[uuid].after)
          if (antmBindingObjs[uuid].opacity) i.target.style.opacity = 1
        })
    }
  }
}
let antmObserver: IntersectionObserver | null = null
try {
  antmObserver = new IntersectionObserver(antmCallback)
} catch (error) {
  antmObserver = null
}
const initBinding = (value: number | antmType) => {
  const initObj = {
    time: [0],
    child_node: false,
    before: '',
    after: 'animation_start',
    opacity: true
  }
  if (typeof value === 'number') {
    initObj.time = [value]
    return initObj
  } else
    return {
      ...initObj,
      ...value,
      time: typeof value.time === 'number' && !value.child_node ? [value.time] : value.time
    }
}
export interface antmType {
  time: number | number[] //当child_node 为true的时候 值为间隔
  child_node?: boolean //是否将所有子节点加入
  before?: string | string[] //触发前 class
  after?: string | string[] //触发后 class
  opacity?: boolean //触发前透明
}

let uuid: number = 0
export const antm = {
  beforeMount(el: Element, binding: { value: number | antmType }) {
    const bindingM = initBinding(binding.value)
    antmBindingObjs[uuid] = bindingM
    if (bindingM.child_node)
      bindingM.opacity &&
        el.childNodes.forEach((childNode: any) => {
          childNode.style.opacity = 0
        })
    else bindingM.opacity && (el.style.opacity = 0)
    el.setAttribute('antm-id', uuid as unknown as string)
    ++uuid
    antmObserver?.observe(el)
  },
  beforeUnmount(el: Element) {
    antmObserver?.unobserve(el)
  }
}

transition.scss

/* fade */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.28s;
}

.fade-enter,
.fade-leave-active {
  opacity: 0;
}

/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
  transition: all 0.3s;
}

.fade-transform-enter-from {
  opacity: 0;
  transform: translateX(-30px);
}

.fade-transform-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

/* breadcrumb transition */
.breadcrumb-enter-active {
  transition: all 0.4s;
}

.breadcrumb-leave-active {
  position: absolute;
  transition: all 0.3s;
}

.breadcrumb-enter-from,
.breadcrumb-leave-active {
  opacity: 0;
  transform: translateX(20px);
}

/**
 * @description 重置el-menu的展开收起动画时长
 */
.outer-most .el-collapse-transition-leave-active,
.outer-most .el-collapse-transition-enter-active {
  transition: 0.2s all ease-in-out !important;
}

.horizontal-collapse-transition {
  transition: var(--pure-transition-duration) all !important;
}

@keyframes downUp {
  0% {
    opacity: 0;
    transform: translateY(calc(100% + 400px));
  }

  30% {
    transform: translateY(-30px);
  }

  60% {
    transform: translateY(10px);
  }

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

.animation_start {
  animation: downUp 2s;
}


@keyframes animation_left {
  0% {
    opacity: 0;
    transform: translateX(calc(-100% - 400px));
  }

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

@keyframes animation_right {
  0% {
    opacity: 0;
    transform: translateX(calc(100% + 400px));
  }

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

.animation_left {
  animation: animation_left 1s;
}

.animation_right {
  animation: animation_right 1s;
}

main

app.directive('lazy', LazyImg)
app.directive('antm', antm)

App.vue

 <div v-antm="{time: 100,child_node: true}"></div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值