Vue implements scrolling layout CSS effect under the carousel map of DingTalk official website

foreword

  • Recently, when I was writing the owner’s side of the PC side, I found that the traditional menu bar is ugly and does not meet the actual application (there are not many functional pages-the display is the main thing)

  • I accidentally discovered that the effect of DingTalk's official website is quite interesting. I thought about restoring this effect, and then searched it.

  • After a while of cv play, plus tinkering, the general effect was adjusted. The time relationship is the most basic, and the rest can be supplemented by yourself.

video effects

Official website effect

detail

1. The second screen in the code is 300vh, which is 3 times. I have tried many times, and the effect is the best when scrolling at 3 times. It is not recommended to change it. It is recommended not to display the scroll bar (src/styles/index.scss) for the best effect

::-webkit-scrollbar {
  // 隐藏滚动条
  display: none; /* Chrome Safari */
}

2. It is best not to change the three class names on the second screen in the code, because the DOM operation is obtained based on these class names

3. The data-order="0" in the list-itme in the second screen in the code is equal to how much (starting from 0) to control the animation box order, you can debug it yourself to see the effect

Full code - reproducible

<template>
  <div class="conter">
    <!-- 第一屏 -->
    <div class="flatly-itemone">
    </div>
    <!-- 第二屏 -->
    <div class="playground">
      <div class="animation-container">
        <div class="titlemanifesto" v-if="titlemanifesto">
          生活意义-坦然面对生活并且接受她的事与愿违
        </div>
        <!-- data-order="0" 数字是控制每一项动画顺序 -->
        <div class="list">
          <div data-order="0" class="list-item"></div>
          <div data-order="1" class="list-item"></div>
          <div data-order="2" class="list-item"></div>
          <div data-order="2" class="list-item"></div>
          <div data-order="1" class="list-item"></div>
          <div data-order="0" class="list-item"></div>
          <div data-order="0" class="list-item"></div>
          <div data-order="1" class="list-item"></div>
          <div data-order="2" class="list-item"></div>
          <div data-order="2" class="list-item"></div>
          <div data-order="1" class="list-item"></div>
          <div data-order="0" class="list-item"></div>
        </div>
      </div>
    </div>
  </div>
</template>
​
<script>
export default {
  name: 'Dashboard',
  data() {
    return {
      animataionMap: new Map(),
      // 文字显示
      titlemanifesto: false
    }
  },
  created() {},
  mounted() {
    this.updateMap(),
      this.updateStyle(),
      window.addEventListener('scroll', this.updateStyle)
  },
  methods: {
    // 得出动画节点数值
    createAnimation(scrollStart, scrollEnd, valueStart, valueEnd) {
      return (scroll) => {
        if (scroll <= scrollStart) {
          return valueStart
        }
​
        if (scroll >= scrollEnd) {
          return valueEnd
        }
​
        return (
          valueStart +
          ((valueEnd - valueStart) * (scroll - scrollStart)) /
            (scrollEnd - scrollStart)
        )
      }
    },
​
    getDomAnimation(scrollStart, scrollEnd, dom) {
      const list = document.querySelector('.list')
      scrollStart = scrollStart + dom.dataset.order * 300
      const opacityAnimation = this.createAnimation(
        scrollStart,
        scrollEnd,
        0,
        1
      )
      // 基于当前滚动计算得出的透明度
      const opacity = function (scroll) {
        return opacityAnimation(scroll)
      }
​
      const scaleAnimation = this.createAnimation(
        scrollStart,
        scrollEnd,
        0.3,
        1
      )
​
      const xAnimation = this.createAnimation(
        scrollStart,
        scrollEnd,
        list.clientWidth / 2 - dom.offsetLeft - dom.clientWidth / 2,
        0
      )
      const yAnimation = this.createAnimation(
        scrollStart,
        scrollEnd,
        list.clientHeight / 2 - dom.offsetTop - dom.clientHeight / 2,
        0
      )
​
      const transform = function (scroll) {
        return `translate(${xAnimation(scroll)}px,${yAnimation(
          scroll
        )}px)  scale(${scaleAnimation(scroll)})`
      }
​
      return {
        opacity,
        transform
      }
    },
​
    updateMap() {
      const items = document.querySelectorAll('.list-item')
      const playGround = document.querySelector('.playground')
      this.animataionMap.clear()
      const playGroundRect = playGround.getBoundingClientRect()
      // 开始动画的距离
      const scrollStart = playGroundRect.top + window.scrollY
      // 结束动画的距离  相当于playground的高度
      const scrollEnd =
        playGroundRect.bottom + window.scrollY - window.innerHeight
      for (const item of items) {
        this.animataionMap.set(
          item,
          this.getDomAnimation(scrollStart, scrollEnd, item)
        )
      }
      // 打开遮罩层
      // this.listmsk = true
    },
​
    updateStyle() {
      const scroll = window.scrollY
      // 获取元素-改变背景颜色
      const list = document.querySelector('.list')
      if (scroll > 2200 && scroll < 2862) {
        console.log('打开遮罩层')
        list.style.backgroundColor = 'rgba(23, 26, 29, 0.9)'
        // 显示文字
        this.titlemanifesto = true;
      } else {
        console.log('关闭遮罩层')
        list.style.backgroundColor = '#063868'
        // 隐藏文字
        this.titlemanifesto = false
      }
      console.log('scroll', scroll)
      for (let [dom, value] of this.animataionMap) {
        for (const cssProp in value) {
          dom.style[cssProp] = value[cssProp](scroll)
        }
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.conter {
  .flatly-itemone {
    height: 90vh;
    background-color: #fff;
  }
  .playground {
    height: 310vh;
    background-color: #063868;
    position: relative;
    .animation-container {
      display: flex;
      position: sticky;
      top: 0;
      height: 100vh;
      text {
        z-index: 999;
        color: red;
      }
      // 标题
      .titlemanifesto {
        height: 50px;
        width: 1000px;
        position: absolute;
        left: 50%;
        top: 23%;
        transform: translate(-50%);
        // background-color: skyblue;
        text-align: center;
        color: #fff;
        font-family: PingFangSC-Medium;
        font-weight: 500;
        font-size: 30px;
        line-height: 50px;
      }
      .list {
        height: 550px;
        width: 1000px;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -28%);
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        border-radius: 10px;
        padding: 15px 20px;
        opacity: 0.8;
        .list-item {
          width: 100px;
          height: 155px;
          border-radius: 10px;
          background-color: #fff;
          margin: 50px 30px;
          &:nth-child(2n - 1) {
            background-color: skyblue;
          }
          &:nth-child(2n) {
            background-color: rgb(111, 245, 111);
          }
          &:nth-child(3n) {
            background-color: orange;
          }
        }
      }
    }
  }
}
</style>

Summarize:

After this process, I believe you have a preliminary deep impression on Vue's implementation of scrolling typesetting CSS effect under the carousel chart of DingTalk's official website, but the situation we encounter in actual development is definitely different, so we To understand its principle, everything changes. Come on, hit the workers!

Please point out any deficiencies, thank you -- Fengguowuhen

Guess you like

Origin blog.csdn.net/weixin_53579656/article/details/131445013