vue+vant实现浮动导航栏点击定位到模块,且选中效果随滚动切换

发布时间 2023-06-16 15:06:30作者: 芝麻小仙女

1.主页面中导入浮动导航栏(使用vant的粘性布局sticky组件,使首屏下方的导航栏随页面滚动浮动在想要的位置):

<template>
  <div class="app-container">
    <!-- 浮动导航 -->
    <van-sticky
      style="
        z-index: 1;
        position: absolute;
        top: 12.34rem;
        left: 0;
        width: 100%;
        height: 0.76rem;
      "
      offset-top="0.95rem"
    >
      <tabs-index />
    </van-sticky>
    <top-index @login="toLogin" @bind="toBindRole" />
// 这里省略页面的主要内容(即浮动栏可切换的模块内容)
    <foot-index />
    <login-index ref="login" />
    <bind-index ref="bind" />
  </div>
</template>

<script>
import store from "@/store";
import { mapGetters, mapActions } from "vuex";
import TabsIndex from "@/components/TheTabs/TabsIndex";
import TopIndex from "@/components/TheTop/TopIndex";
import LoginIndex from "@/components/TheLogin/LoginIndex";
import BindIndex from "@/components/TheBindRule/BindIndex";
import FootIndex from "@/components/TheFoot/FootIndex";

export default {
  name: "App",
  components: {
    TopIndex,
    LoginIndex,
    TabsIndex,
    BindIndex,
    FootIndex,
  },
  computed: {
    ...mapGetters(["token", "roleId"]),
  },
  mounted() {
  },
  methods: {
    ...mapActions([
      "setUser",
      "setPhone",
    ]),
  },
};
</script>

  

2.导航栏代码:

<!-- tabs -->
<template>
  <aside>
    <div :class="$style.wrap" :style="{ ...otherStyle }">
      <ul :class="$style.tabs">
        <li
          v-for="(el, index) in tabList"
          :key="index"
          :class="[
            $style.li,
            activeKey === el.value ? $style.active : '',
            index === 1 && creativeInfo.status && creativeInfo.status === 1
              ? $style.entries
              : '',
          ]"
          @click="checkTab(el.value, index)"
        >
          <div
            :class="[$style.itemText]"
            :style="{
              backgroundPosition:
                index === 3 && creativeInfo.vote_status === 2
                  ? `${-(0.93 * 4)}rem 0`
                  : `${-(0.93 * index)}rem 0`,
            }"
          ></div>
        </li>
      </ul>
    </div>
  </aside>
</template>
<script>
import { mapGetters, mapActions } from "vuex";

export default {
  name: "TabsIndex",
  components: {},
  props: {
    otherStyle: {
      type: Object,
      default() {
        return {};
      },
    },
  },
  data() {
    return {
      tabList: [{ value: "1" }, { value: "2" }, { value: "3" }, { value: "4" }],
      activeKey: "1"
    };
  },
  computed: {
    ...mapGetters(["roleGifts", "creativeInfo"]),
  },
  mounted() {
    window.addEventListener("scroll", this.onScroll);
  },
  destroyed() {
    window.removeEventListener("scroll", this.onScroll);
  },
  methods: {
    ...mapActions(["setLikeData"]),
    pxToRem(num) {
      const { clientWidth } = document.body;
      if (clientWidth >= 750) {
        return num;
      }
      return num * (clientWidth / 750);
    },
    // 点击tab
    checkTab(bind_id) {
      this.activeKey = bind_id;
      const TARGET = {
        "1": "first",
        "2": "second",
        "3": "third",
        "4": "four",
      };
      if (bind_id) {
        const targetObj = document.querySelector(`#j-${TARGET[bind_id]}`);
        if (targetObj) {
          const { offsetTop } = targetObj;
          const scrollTop = offsetTop - this.pxToRem(0);
          document.body.scrollTop = scrollTop;
          document.documentElement.scrollTop = scrollTop;
        }
      }
    },
    onScroll(){
      // 获取所有锚点元素
      const targetObj = document.querySelectorAll(`.tabContent`);
      // 获取所有锚点元素的offsetTop
      const offsetTopArr = [];
      targetObj.forEach(item => {
        offsetTopArr.push(item.offsetTop);
      });
      // 获取当前文档流的 scrollTop
      const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
      // 定义当前点亮的导航下标
      let navIndex = 0;
      for (let n = 0; n < offsetTopArr.length; n++) {
        // 如果scrollTop大于等于第n个元素的ofssetTop,则说明第n-1个元素的内容完全不可见,此时导航索引就是n
        if (scrollTop >= offsetTopArr[n]) {
          navIndex = n;
        }
      }
      this.activeKey = String(navIndex + 1);
    }
  },
};
</script>

<style lang="less" module>
.wrap {
  width: 100%;
  height: 0.76rem;
  display: flex;
  justify-content: center;
  > div:first-child {
    height: 100%;
  }
}
.li {
  position: relative;
  width: 23%;
  height: 0.5rem;
  text-align: center;
  line-height: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 1%;
}
.itemText {
  .size(0.92rem, 0.24rem);
  .background-fill("./images/tab_title.png", 500% 100%);
}
.active {
  background-color: #d9c9c5;
}
.entries {
  position: relative;
  &::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    width: 0.25rem;
    height: 0.25rem;
    .background-fill("./images/tab_new.png");
  }
}
.tabs {
  width: 6.52rem;
  height: 0.76rem;
  .background-fill("./images/tab_bg.png");
  display: flex;
  justify-content: space-between;
  padding: 0.12rem 0.32rem;
  box-sizing: border-box;
  > li {
    &::before {
      content: "|";
      position: absolute;
      left: 102%;
      bottom: 0;
      top: 0.14rem;
      color: #6a4a19;
      font-size: 0.2rem;
      pointer-events: none;
    }
  }
  > li:last-child {
    &::before {
      display: none;
    }
  }
}
</style>

  

那么这个功能就这么做完了。