锚点定位,菜单焦点随内容变化

该文章展示了如何在Vue.js应用中实现锚点定位,特别是在一个包含多个滚动区域的场景下。通过监听tab点击事件和平滑滚动动画,使得用户在切换标签页时可以平滑滚动到对应的内容区域。同时,代码还处理了滚动条滚动时自动切换激活的tab。
摘要由CSDN通过智能技术生成

js 锚点定位

<!DOCTYPE html>
<html>
<head>
  <style>
    div {
      height: 800px;
      width: 400px;
      border: 2px solid black;
    }
    h2 {
      position: fixed;
      margin:50px 500px;
    }
  </style>
</head>
<body>
  <h2>
    <a href="#div1" rel="external nofollow" >to div1</a>
    <a href="#div2" rel="external nofollow" >to div2</a>
    <a href="#div3" rel="external nofollow" >to div3</a>
  </h2>
  <div id="div1">div1</div>
  <div id="div2">div2</div>
  <div id="div3">div3</div>
</body>
</html>

vue 的锚点定位

<template>
    <div>
    <el-tabs
      class="fixed-header-left-person"
      tab-position="left"
      @tab-click="jump"
      v-model="tabName"
    >
      <el-tab-pane
        v-for="(tab, index) in tabs"
        :name="tab.refName"
        :key="index"
        :label="tab.name"
      ></el-tab-pane>
    </el-tabs>
    <div
      class="scroll-content"
      @scroll="onScroll"
      :style="
        'overflow-x: hidden; overflow-y: auto;height:' + contentStyleObj.height
      "
    >
      <!-- 用户管理 -->
      <div :ref="tabs[0].refName" class="scroll-item">
        <div class="line-name">
          <h2>{{ tabs[0].name }}</h2>
        </div>
        <div>
          <p
            style="height: 40px"
            v-for="item in [ 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]"
            :key="item"
          >
            待发货符合规范化如故
          </p>
        </div>
      </div>
      <!-- 配置管理 -->
      <div :ref="tabs[1].refName" class="scroll-item">
          <div class="line-name">
          <h2>{{ tabs[1].name }}</h2>
        </div>
        <div>
          <p
            style="height: 40px"
            v-for="item in [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]"
            :key="item"
          >
            新能说出的基本功发到你DNF不得发布
          </p>
        </div>
      </div>
      <!-- 角色管理 -->
      <div
        :ref="tabs[2].refName"
        class="scroll-item"
        style="padding-top: 1rem; top: 5px"
      >
      <div class="line-name">
          <h2>{{ tabs[2].name }}</h2>
        </div>
        <div>
          <p
            v-for="item in [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]"
            :key="item"
          >
            新水泥厂剧场版
          </p>
        </div>
      </div>
      <!-- 角色管理2 -->
      <div
        :ref="tabs[3].refName"
        class="scroll-item"
        style="padding-top: 1rem; top: 5px"
      >
      <div class="line-name">
          <h2>{{ tabs[3].name }}</h2>
        </div>
        <div>
          <p
            v-for="item in [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ]"
            :key="item"
          >
            新水泥厂剧场版
          </p>
        </div>
      </div>
    </div>

    </div>
</template>

<script>
export default {
  name: 'index',
  props: {},
  components: {},
  data() {
    return {
      tabIndex: '0',
      contentStyleObj: {
        height: '100px',
      },
      tabName: 'setOneRef',
      tabs: [
        {
          name: '用户管理',
          refName: 'setOneRef',
        },
        {
          name: '配置管理',
          refName: 'setTwoRef',
        },
        {
          name: '角色管理',
          refName: 'setThreeRef',
        },
        {
          name: '角色管理2',
          refName: 'setFourRef',
        },
      ],
    }
  },
  computed: {},
  watch: {},
  created() {
    this.getHight()
    window.addEventListener('resize', this.getHight)
  },
  destroyed() {
    window.removeEventListener('resize', this.getHight)
  },
  methods: {
    // tab click
    jump(tab, event) {
      let target = document.querySelector('.scroll-content')
      let scrollItems = document.querySelectorAll('.scroll-item')
      // 判断滚动条是否滚动到底部
      if (target.scrollHeight <= target.scrollTop + target.clientHeight) {
        this.tabIndex = tab.index.toString()
      }
      let totalY = scrollItems[tab.index].offsetTop - scrollItems[0].offsetTop // 锚点元素距离其offsetParent(这里是body)顶部的距离(待滚动的距离)
      let distance = document.querySelector('.scroll-content').scrollTop // 滚动条距离滚动区域顶部的距离
      // let distance = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset // 滚动条距离滚动区域顶部的距离(滚动区域为窗口)
      // 滚动动画实现, 使用setTimeout的递归实现平滑滚动,将距离细分为50小段,10ms滚动一次
      // 计算每一小段的距离
      let step = totalY / 50
      if (totalY > distance) {
        smoothDown(document.querySelector('.scroll-content'))
      } else {
        let newTotal = distance - totalY
        step = newTotal / 50
        smoothUp(document.querySelector('.scroll-content'))
      }

      // 参数element为滚动区域
      function smoothDown(element) {
        if (distance < totalY) {
          distance += step
          element.scrollTop = distance
          setTimeout(smoothDown.bind(this, element), 10)
        } else {
          element.scrollTop = totalY
        }
      }

      // 参数element为滚动区域
      function smoothUp(element) {
        if (distance > totalY) {
          distance -= step
          element.scrollTop = distance
          setTimeout(smoothUp.bind(this, element), 10)
        } else {
          element.scrollTop = totalY
        }
      }
    },
    // 滚动条滚动
    onScroll(e) {
      let scrollItems = document.querySelectorAll('.scroll-item')
      for (let i = scrollItems.length - 1; i >= 0; i--) {
        // 判断滚动条滚动距离是否大于当前滚动项可滚动距离
        let judge =
          e.target.scrollTop >=
          scrollItems[i].offsetTop - scrollItems[0].offsetTop - 400
        if (judge) {
          this.tabIndex = i.toString()
          // 找对应的tab-name值
          this.tabName = this.tabs[this.tabIndex].refName
          break
        }
      }
    },
    getHight() {
      this.contentStyleObj.height = window.innerHeight - 190 + 'px'
    },
  },
}
</script>

<style scoped>

.fixed-header-left-person /deep/.el-tabs__item{
    height: 27px;
    width: 80px;
    line-height: 22px;
    border: none;
    border-radius: 4px;
    padding: 4px !important;
    margin: 0px;
    text-align: center;
}
.fixed-header-left-person{
    float: left;
    width: 80px;
}
.fixed-header-left-person /deep/ .el-tabs__nav-wrap{
  position: relative;
  left:0px;
  top: 0px;
  width: 80px;
  display:inline-block;
  z-index: 99;
}
.fixed-header-left-person /deep/ .el-tabs__content {
  margin-right: 90px;
}

.fixed-header-left-person /deep/ .el-tabs__nav-scroll {
    display:inline-block;
    height: auto !important;
}
.fixed-header-left-person /deep/ .el-tabs__nav-wrap {
    display:inline-block;
    height: auto !important;
}
.scroll-content{
    margin-left: 90px;
}
</style>

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值