These days to write requirements, write a TAB switch + page scrolling linkage effect, although it is not difficult, but I think it is quite necessary to record, because this kind of scene is also quite common, so that the next time encounter similar, can directly use.

Here’s what the page looks like:

Code:

<template>
  <div class="box">
    <div class="tab" ref="tab">
      <div v-for="(item, index) in tabs" :key="index">
        <div :class="{ active: active === index }" @click="switchTab(index)">
          {{ item }}
        </div>
      </div>
    </div>
    <div class="cont" ref="cont">
      <div class="cont_1" ref="cont_1"</div> <div class="cont_2" ref="cont_2"</div> <div class="cont_3" ref="cont_3"</div> </div> <div class="back-top" @click="backTop"></div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      tabs: ["tab1"."tab2"."tab3"],
      active: 0,
      cont1: null,
      cont2: null,
      cont3: null,
      isClickTab: false
    };
  },
  methods: {
    backTop() {
      this.cont1.scrollIntoView({
        block: "start",
        behavior: "smooth"
      });
    },
    switchTab(index) {
      if (index === 0) {
        this.cont1.scrollIntoView({
          block: "start",
          behavior: "smooth"
        });
      } else if (index === 1) {
        this.cont2.scrollIntoView({
          block: "start",
          behavior: "smooth"
        });
      } else {
        this.cont3.scrollIntoView({
          block: "start",
          behavior: "smooth"}); }}},mounted() {
    this.cont1 = this.$refs["cont_1"];
    this.cont2 = this.$refs["cont_2"];
    this.cont3 = this.$refs["cont_3"];
    const tabH = this.$refs["tab"].offsetHeight;
    this.$refs["cont"].addEventListener("scroll", () = > {if (this.cont3.getBoundingClientRect().top <= tabH) {
        this.active = 2;
        return false;
      }
      if (this.cont2.getBoundingClientRect().top <= tabH) {
        this.active = 1;
        return false;
      }
      if(this.cont1.getBoundingClientRect().top <= tabH) { this.active = 0; }}); }}; </script> <style lang="scss" scoped>
.box {
  font-size: 28px;
  overflow-x: auto;
  height: 100vh;
  display: -webkit-flex;
  display: flex;
  flex-direction: column;
  overflow-y: hidden;
  .tab {
    height: 88px;
    background: #fff;
    line-height: 88px;
    color: # 666;
    display: -webkit-flex;
    display: flex;
    justify-content: space-around;
    .active {
      font-size: 32px;
      color: # 333;
      &::after {
        display: block;
        content: ""; width: 36px; height: 6px; margin: auto; margin-top: -10px; background: rgba(255, 51, 0, 1); border-radius: 3px; } } } .cont { height: 300px; flex-grow: 1; overflow: auto; .cont_1 { height: 400px; background: pink; } .cont_2 { height: 800px; background: yellow; } .cont_3 { height: 100%; background: lightgreen; } } .back-top { width: 80px; height: 80px; background: url(.. /.. /assets/back-top.png) center / 100% 100% no-repeat; border-radius: 50%; position: fixed; bottom: 120px; right: 32px; } } </style>Copy the code

Key points:

  • ScrollIntoView scroll to the designated area, and can set animation effects, most browsers support, more should be no problem in the mobile terminal.
  • GetBoundingClientRect this method can obtain the distance to the current element from the window of the up and down or so, the console to see:

    Using this API saves a lot of computation trouble.

Summary: Mainly the use of these two apis together. When the TAB to switch, use scrollIntoView triggered the scroll event, the scroll event listeners getBoundingClientRect. Top, find the value is less than or equal to the height of the TAB, that has been into the region, changes the value of the active TAB style will change Changed. Conversely, if the page is manually scrolling, the Scroll event will be triggered directly, which will also change the value of active and control the change of TAB style.