vue3

vue3.0入场动画

<template>
  <div class="live-across-sub" id="animate">
    <button @click="addFun">测试+1</button>
    <div class="animate-slide">
      <div
        class="animate-slide__li"
        v-for="item in moveList"
        :key="item"
        :id="item.id"
        :class="item.classRank"
      >
        <div class="animate-slide__li--avatar">
          <img :src="avatar" />
        </div>
        <div class="animate-slide__li--content">
          <span :style="{ color: nameColor }" class="name">{{ name }}</span>
          <span class="text">{{ text }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
const props = defineProps({
  avatar: {
    type: String,
    default:
      'https://img10.360buyimg.com/ling/jfs/t1/181258/24/10385/53029/60d04978Ef21f2d42/92baeb21f907cd24.jpg'
  },
  name: {
    type: String,
    default: '小张'
  },
  nameColor: {
    type: String,
    default: '#ffa95a'
  },
  text: {
    type: String,
    default: '进入直播间'
  }
})

let moveList = ref([])
const data = reactive({
  num: 0,
  waitList: [],
  delList: [],
  classList: ['frist', 'two', 'three'],
  classCurr: computed(() => {
    let getListval = Array.from(moveList.value, ({ classRank }) => classRank)
    if (getListval.indexOf(data.classList[0]) === -1) {
      return data.classList[0]
    }
    if (getListval.indexOf(data.classList[1]) === -1) {
      return data.classList[1]
    }
    if (getListval.indexOf(data.classList[2]) === -1) {
      return data.classList[2]
    }
  })
})

const addFun = () => {
  data.num++
  if (moveList.value.length < 3) {
    let obj = {
      id: data.num,
      classRank: data.classCurr
    }
    moveList.value.push(obj)
  } else {
    data.waitList.push(data.num)
  }
}

const addWait = () => {
  if (data.waitList.length > 0) {
    let obj = {
      id: data.waitList[0],
      classRank: data.classCurr
    }
    moveList.value.push(obj)
    data.waitList = data.waitList.slice(1)
  }
}

function listenerFun(e) {
  // console.log('e:', e)
  if (moveList.value.length > 0) {
    if (data.delList.indexOf(e.target.id) > -1) {
      moveList.value = moveList.value.filter(ele => ele.id != e.target.id)
      return
    }
    setTimeout(() => {
      let getDom = document.getElementById(e.target.id)
      getDom.className = getDom.className + ' out'
      data.delList.push(e.target.id)
    }, 1500)
  }
}

onMounted(() => {
  document.addEventListener('animationend', listenerFun, false)
})

onBeforeUnmount(() => {
  document.removeEventListener('animationend', listenerFun, false)
})

watch(
  () => moveList,
  (newVal, oldVal) => {
    if (newVal.length < 3 && data.waitList.length > 0) {
      addWait()
    }
  },
  { deep: true }
)
</script>

<style lang="scss" scoped>
.live-across-sub {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}
.animate-slide {
  display: flex;
  flex-direction: column;
  position: absolute;
  top: 26px;
  left: 0;
  right: 0;
  min-height: 128px;
  &__li {
    border-radius: 20px;
    background-color: #fff;
    display: flex;
    flex-wrap: nowrap;
    position: absolute;
    animation: moveIn 3s linear;
    &--avatar {
      display: inline-block;
      width: 36px;
      height: 36px;
      border-radius: 50%;
      overflow: hidden;
      vertical-align: middle;
      margin-right: 10px;
      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
    }
    &--content {
      margin-right: 12px;
      line-height: 36px;
      font-size: 14px;
      color: #000;
      white-space: nowrap;
      .name {
        margin-right: 5px;
      }
    }
  }
  .out {
    animation: moveOut 2s linear;
  }
  .frist {
    top: 0;
  }
  .two {
    top: 51px;
  }
  .three {
    top: 102px;
  }
  @keyframes moveIn {
    from {
      left: 100%;
    }

    to {
      left: 0;
    }
  }
  @keyframes moveOut {
    0% {
      opacity: 1;
      transform: translateX(-9px);
    }

    50% {
      opacity: 1;
      transform: translateX(9px);
    }
    /* 50% {
      opacity: 1;
      transform: translateX(0);
    } */
    100% {
      opacity: 0;
      transform: translateX(-100%);
    }
  }
}
</style>
上次更新: