vue 侧边导航栏与内容联动组件

890 阅读1分钟

记录一个vue侧边导航栏组件,可以与内容联动,话不多说上代码:

html:
<template>
  <div class="app">
    <div class="nav" id="box_action_translateYOut">
      <div class="nav_box" v-for="(item, index) in stepList" :key="index" :class="{ navActive: currentIndex === index }">
        <div v-show="currentIndex !== index"></div>
        <svg-icon v-show="currentIndex === index" class-name="fswx-icon" icon-class="fswx-selected" />
        <a :href="'#' + item.value" @click="goStep(item.value)">{{ item.name }}</a>
      </div>
      <div class="fswx-switch-btn">
        <a :href="'#' + id" @click="goLastStep">
          <svg-icon class-name="fswx-icon" icon-class="fswx-top-switch" />
        </a>
        <a :href="'#' + id" @click="goNestStep">
          <svg-icon class-name="fswx-icon" icon-class="fswx-bottom-switch" />
        </a>
      </div>
    </div>
  </div>
</template>
js:
export default {
  props: {
    stepList: {
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data() {
    return {
      currentIndex: 0,
      heightArr: [],
      id: 0,
      stopScroll: false
    }
  },
  methods: {
    wrapListener() {
      // 获取wrap元素里所有的a标签元素
      const wrapDom = document.getElementById('box_action_translateYOut')
      const aDom = wrapDom.getElementsByTagName('a')
      const len = aDom.length - 2
      const wrap = this.$parent.$refs.wrap
      const parentRefs = this.$parent.$parent.$refs
      const diff = parentRefs.scrollOne.offsetTop
      for (const key in parentRefs) {
        if (Object.hasOwnProperty.call(parentRefs, key)) {
          const element = parentRefs[key]
          if (element && element.offsetTop) {
            this.heightArr.push(element.offsetTop - diff)
          }
        }
      }
      // wrap可视区域高度
      const domHeight = wrap.clientHeight
      // wrap的滚动条的总高度
      const scrollHeight = wrap.scrollHeight
      window.addEventListener(
        'scroll',
        () => {
          const scrollTop = wrap.scrollTop
          for (let i = 0; i < len; i++) {
            if (scrollTop > this.heightArr[i] && scrollTop < this.heightArr[i + 1] && i < len - 1) {
              this.currentIndex = i
            } else if (i === len - 1) {
              // 最后一项
              if (scrollTop > this.heightArr[i]) {
                this.currentIndex = i
              }
            }
          }
          // 滚动到底部的条件
          if (scrollTop + domHeight === scrollHeight) {
            this.currentIndex = len - 1
          }
          if (this.stopScroll) {
            this.currentIndex = this.id - 1
          }
          this.stopScroll = false
        },
        true
      )
    },
    goStep(id) {
      this.id = id
      this.stopScroll = true
      this.currentIndex = id - 1
    },
    goLastStep() {
      if (this.currentIndex > 0) {
        this.id = this.currentIndex
        this.currentIndex = this.currentIndex - 1
        this.stopScroll = true
      }
    },
    goNestStep() {
      if (this.id < 9) {
        this.id = this.currentIndex + 2
        this.currentIndex = this.currentIndex + 1
        this.stopScroll = true
      }
    }
  },
  mounted() {
    this.wrapListener()
  }
}
css:
.app {
  .nav {
    width: 142px;
    position: fixed;
    bottom: 4%;
    right: 50px;
    z-index: 99;
    .nav_box {
      display: flex;
      margin-bottom: 15px;
      position: relative;
      cursor: pointer;
      div {
        width: 6px;
        height: 6px;
        border-radius: 6px;
        background-color: #000;
        margin-right: 9px;
        margin-top: 3px;
      }
      a {
        display: inline-block;
        width: 126px;
        font-size: 16px;
        color: #303133;
        text-decoration: none;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
    .nav_box::after {
      content: '';
      width: 1px;
      height: 25px;
      background-color: #d8d8d8;
      position: absolute;
      left: 2%;
      bottom: 85%;
    }
    .nav_box:nth-child(1)::after {
      content: '';
      width: 0;
      height: 0;
      background-color: #d8d8d8;
      position: absolute;
      left: 4%;
      bottom: 10%;
    }
    // 点击导航的高亮样式
    .navActive {
      display: flex;
      margin-bottom: 15px;
      cursor: pointer;
      .fswx-icon {
        font-size: 10px;
        margin-right: 6px;
        margin-top: 2px;
        margin-left: -2px;
        z-index: 9;
        @include theme_color;
      }
      a {
        display: inline-block;
        width: 126px;
        font-size: 16px;
        @include theme_color;
        // color: #2d54b8;
        text-decoration: none;
        font-weight: 700;
      }
    }
    .fswx-switch-btn {
      position: absolute;
      top: 50%;
      right: -24px;
      margin-top: -28px;
      border: 1px solid #e4e4e4;
      border-radius: 9px;
      a:nth-child(1) {
        border-bottom: 1px solid #e4e4e4;
      }
      .fswx-icon {
        font-size: 9px;
        padding: 3px;
      }
      a {
        cursor: pointer;
        text-decoration: none;
        display: block;
        color: #606266;
      }
    }
  }
}

效果:

image.png