您好,欢迎来到华佗小知识。
搜索
您的当前位置:首页vue3中web前端JS动画案例(四)侧边栏横幅效果-右下角广告-淘宝案例

vue3中web前端JS动画案例(四)侧边栏横幅效果-右下角广告-淘宝案例

来源:华佗小知识

/**
 * 动画的函数
 * dom 当前对象
 * JSON 传入元素对象的属性 {"width": 300, "opacity": 50}
 * 
 * -------------------- 多物体运动,同时运动 ---传入JSON-------------
 */
let speed1 = 0
export function startAnimation2(dom, JSON, fn) {
  // 注意:针对于多物体运动,定时器的返回值要绑定当前的对象中。offsetWidth获取的是包括border的宽度,所以这里使用getComputed获取width
  clearInterval(dom.timer)
  dom.timer = setInterval(() => {
    let cur = 0
    let flag = true // 标杆 如果true,证明所有的属性都到达终点值
    // 0 获取样式属性
    for (let attr in JSON) {
      switch (attr) {
        case 'opacity':
          cur = Math.round(parseFloat(getStyle(dom, attr)) * 100)
          break;
        case 'scrollTop':
          cur = dom[attr]
          break;
        default:
          cur = parseInt(getStyle(dom, attr))
          break;
      }
      // if (attr === 'opacity') {
      //   // 求透明度的变化速度,注意!小数需要取整
      //   cur = Math.round(parseFloat(getStyle(dom, attr)) * 100)
      // } else {
      //   // 获取dom宽度或高度等
      //   cur = parseInt(getStyle(dom, attr))
      // }

      // 1、求速度
      speed1 = (JSON[attr] - cur) / 20
      speed1 = JSON[attr] > cur ? Math.ceil(speed1) : Math.floor(speed1)

      // 2、临界处理
      if (JSON[attr] !== cur) {
        flag = false
      }
      // 3、运动起来
      switch (attr) {
        case 'opacity':
          dom.style[attr] = `alpha(opacity=${cur + speed1})`
          dom.style[attr] = (cur + speed1) / 100
          break;
        case 'scrollTop':
          dom[attr] = cur + speed1
          break;
        default:
          dom.style[attr] = cur + speed1 + 'px'
          break;
      }
      // if (attr === 'opacity') {
      //   dom.style[attr] = `alpha(opacity=${cur + speed1})`
      //   dom.style[attr] = (cur + speed1) / 100
      // } else {
      //   dom.style[attr] = cur + speed1 + 'px'
      // }
    }

    if (flag) {
      clearInterval(dom.timer)
      if (fn) {
        fn()
      }
      return
    }
  }, 30)


  // dom 是对象, attr 是什么属性
  // 获取元素属性的方法
  function getStyle(dom, attr) {
    if (dom.currentStyle) {
      // 针对IE浏览器
      return dom.currentStyle[attr]
    } else {
      // 针对 Firefox浏览器
      return getComputedStyle(dom, null)[attr]
    }
  }
}

 index.vue

<script setup>
import { ref, onMounted, onUnmounted, nextTick, watch, reactive } from 'vue'
import { startAnimation2 } from './MyJSAnimation/myJsAnimation2'
// ----------------------- 08 联动效果 ---------------------
// 1、联动效果
// 2、侧边栏横幅
// 3、滚动监听
// 4、轮播图


// ------------- 1 右下角联动效果 ------------------
const adRef = ref(null)
const close = () => {
  startAnimation2(adRef.value, { "height": 160 }, () => {
    startAnimation2(adRef.value, { "width": 0 }, () => {
      adRef.value.style.display = 'none'
    })
  })
}

// ---------------- 2 左侧边栏横幅 --滚动效果----------------
const asideRef = ref(null)
let aside_top = 0
const raside = ref(null)
const handleScroll = (e) => {
  const lis = raside.value.querySelectorAll('li')

  const scrollTop = window.scrollY || document.documentElement.scrollTop;
  console.log('页面滚动距离:', scrollTop);
  startAnimation2(asideRef.value, { "top": scrollTop + aside_top })

  // 监听页面滚动,选中右边侧边栏
  if (!list.isClick) {
    // 获取页面滚动的高度
    const scrollTop = window.scrollY || document.documentElement.scrollTop;
    for (let i = 0; i < lis.length; i++) {
      if (scrollTop >= list.box[i].offsetTop) {
        list.currentType = list.items[i].type
      }
    }
  }
}

// ----------------3 淘宝案例---------------------
const list = reactive({
  items: [
    { id: 1, name: '爱逛好货', type: '1' },
    { id: 2, name: '好店主播', type: '2' },
    { id: 3, name: '品质特色', type: '3' },
    { id: 4, name: '猜你喜欢', type: '4' }
  ],
  currentType: '1',
  isClick: false, // 是否点击右侧边栏
  box: null, // 所有的大盒子
})
const boxRef = ref(null)
const getStyle = () => {
  // 上色
  const color = ['skyblue', 'orange', 'blue', 'purple']
  for (let index = 0; index < list.box.length; index++) {
    list.box[index].style.backgroundColor = color[index];
  }
}

// 监听右导航器按钮的点击
const handleClickItem = (item, index) => {
  list.isClick = true
  list.currentType = item.type
  nextTick(() => {
    // 文档的顶部到视口顶部的距离 = indx * 文档高度
    // document.documentElement.scrollTop = index * document.body.clientHeight
    // console.log(document.documentElement.scrollTop);
    // 页面动画
    startAnimation2(document.documentElement, { "scrollTop": index * document.body.clientHeight }, () => {
      list.isClick = false
    })

  })
}


onMounted(() => {
  aside_top = asideRef?.value?.offsetTop // 左侧边栏举例顶部的距离
  list.box = boxRef.value.querySelectorAll('div')
  window.addEventListener('scroll', handleScroll);
  getStyle()
})
onUnmounted(() => {
  window.removeEventListener('scroll', handleScroll);
});



</script>

<template>
  <div class="info" id="info">
    <div class="main" id="box" ref="boxRef">
      <div class="current">爱逛好货</div>
      <div>好店主播</div>
      <div>品质特色</div>
      <div>猜你喜欢</div>
    </div>
    <!-- 右导航器 -->
    <ul class="r-aside" ref="raside">
      <li v-for="(item, index) in list.items" :key="item.id"
        :class="`${item.type === list.currentType ? 'active' : ''}`" @click="handleClickItem(item, index)">
        <a href="javascript:void(0)">{{ item.name }}</a>
      </li>

    </ul>
    <!-- 01 右下角广告联动效果 -->
    <div id="ad" ref="adRef">
      <img src="../assets/vue.svg" alt="">
      <span id="close" @click="close">X</span>
    </div>

    <!-- 左侧边栏横幅效果 -->
    <div id="aside" ref="asideRef">
      <img src="../assets/vue.svg" alt="">
    </div>
  </div>
</template>

<style scoped lang="less">
.info {
  display: flex;
  flex-direction: column;
  position: relative;

  .main {
    width: 1190px;
    height: 5000px;
    margin: 0 auto;

    &>div {
      width: 100%;
      height: 100%;
      text-align: center;
      font-size: 30px;
    }
  }


  // 01 联动效果
  #ad {
    position: fixed;
    bottom: 0;
    right: 0;
    background-color: pink;

    img {
      width: 200px;
      height: 200px;
    }

    #close {
      position: absolute;
      top: 0;
      right: 0;
      width: 20px;
      height: 20px;
      text-align: center;
      line-height: 20px;
      cursor: pointer;
      // background-color: skyblue;
      z-index: 5;
    }
  }

  #aside {
    position: absolute;
    top: 200px;
    left: 0;
    // transform: translateY(-50%);
    background-color: pink;

    img {
      width: 100px;
      height: 100px;
    }
  }

  ul {
    list-style: none;
  }

  a {
    text-decoration: none;
  }

  .r-aside {
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 40px;
    font-size: 16px;
    font-weight: 700;
    text-align: center;

    li {
      height: 50px;
      border-bottom: 1px solid #ddd;

      a {
        color: peru;
      }

      &.active {
        background-color: coral;

        a {
          color: #fff;
        }
      }
    }
  }
}
</style>

 

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuo0.cn 版权所有 湘ICP备2023017654号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务