vue实现点击页面侧边导航节点页面滚动到对应section(段落)部分

效果图:

在这里插入图片描述

在这里插入图片描述

index.html(假设该页面要实现点击导航实现滚动功能)

<template>
  <div>
    <el-steps />
    <div class="app-container-details">
      <el-row type="flex" justify="center">
        <el-col :span="23">
          <div class="container-page-main">
            <div class="section-item">
              <el-card class="box-card">
                <div slot="header">
                  <el-row class="item-title">
                    <i class="el-icon-tickets" style="padding: 10px;"> 用户注册</i>
                  </el-row>
                  <div style="height:300px;"></div>
                </div>
              </el-card>
            </div>
            <div class="section-item">
              <el-card class="box-card">
                <div slot="header">
                  <el-row class="item-title">
                    <i class="el-icon-tickets" style="padding: 10px;"> 详细报表</i>
                  </el-row>
                </div>
                2222222222222222222
                <div style="height:300px;"></div>
              </el-card>
            </div>
            <div class="section-item">
              <el-card class="box-card">
                <div slot="header">
                  <el-row class="item-title">
                    <i class="el-icon-tickets" style="padding: 10px;"> 税费情况</i>
                  </el-row>
                </div>
                <div class="main_content">
                  3333333333333
                  <div style="height:300px;"></div>
                </div>
              </el-card>
            </div>
          </div>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

记得放上<el-steps />,我这里是放置与section的父级div平级,实际位置随意,因为右侧的导航定位是position:absolute

<style>
.app-container{
  padding: 90px 100px 10px 15px;  // 设置右侧的padding 100px,是为了给右侧导航条让位置
}
.section-item{
	margin-bottom: 50px; // 让每个section之间上下间隔50px
}
</style>
<script>
import {elSteps} from '@/components'
export default {
  name: 'aaaaaaaaaaa',
  components: {
    elSteps
  },

components/index.js

export { default as elSteps} from './elSteps'

elSteps.vue

<template>
  <el-steps
    class="elSteps"
    direction="vertical"
    :active="active"
    finish-status="wait"
    process-status="finish"
    align-center
  >
    <template v-for="(title,index) in titles">
      <el-step
        :key="index"
        class="title"
        :title="title"
        icon="el-icon-s-opportunity"
        @click.native="scrollToMove(index)"
      ></el-step>
    </template>
  </el-steps>
</template>
<script>
import { slowMove, arrayScroll } from '@/utils/scrollTo'
export default {
  data() {
    return {
      active: 0,
      titles: [],
    }
  },
  mounted: function () {
    const itemTitles = document.querySelectorAll('.item-title')
    console.log('itemTitles:', itemTitles)
    if (itemTitles && itemTitles.length > 0) {
      itemTitles.forEach((itemTitle) => {
        const is = itemTitle.querySelectorAll('i')
        if (is && is.length > 0) {
          this.titles.push(is[0].innerHTML)
        }
      })
    }
    // itemTitles[0].style.color = 'blue'
    this.$nextTick(function () {
      window.addEventListener('scroll', this.onScroll)
    })
  },
  methods: {
    scrollToMove(index) {
      this.active = index
      // item-title为index.html页面的各个section的class名字,通过class获取Dom节点,获取section的名字
      const itemSection = document.querySelectorAll('.item-title')
      // 获取需要滚动的距离
      const total = itemSection[index].offsetTop
      slowMove(total)
    },
    onScroll() {
      this.active = arrayScroll('.item-title', 120)
    },
  },
}
</script>

<style>
.el-step.is-vertical .el-step__title {
  font-size: 12px !important;
  line-height: 25px !important;
  display: flex;
}
.elSteps{
  z-index: 999;
  position: fixed;
  min-height: 250px;
  max-height: 400px;
  right: 15px;
  top: calc((100% - 200px) / 2);
}
.elSteps.el-step__icon {
  background: #f5f7f9 !important;
}
</style>

utils/scrollTo.js

Math.easeInOutQuad = function(t, b, c, d) {
  t /= d / 2
  if (t < 1) {
    return c / 2 * t * t + b
  }
  t--
  return -c / 2 * (t * (t - 2) - 1) + b
}

// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
var requestAnimFrame = (function() {
  return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
})()

/**
 * Because it's so fucking difficult to detect the scrolling element, just move them all
 * @param {number} amount
 */
function move(amount) {
  document.documentElement.scrollTop = amount
  document.body.parentNode.scrollTop = amount
  document.body.scrollTop = amount
}

function position() {
  return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
}

/**
 * @param {number} to
 * @param {number} duration
 * @param {Function} callback
 */
export function scrollTo(to, duration, callback) {
  const start = position()
  const change = to - start
  const increment = 20
  let currentTime = 0
  duration = (typeof (duration) === 'undefined') ? 500 : duration
  var animateScroll = function() {
    // increment the time
    currentTime += increment
    // find the value with the quadratic in-out easing function
    var val = Math.easeInOutQuad(currentTime, start, change, duration)
    // move the document.body
    move(val)
    // do the animation unless its over
    if (currentTime < duration) {
      requestAnimFrame(animateScroll)
    } else {
      if (callback && typeof (callback) === 'function') {
        // the animation is done so lets callback
        callback()
      }
    }
  }
  animateScroll()
}

export function slowMove(total){
  let distance = document.documentElement.scrollTop || document.body.scrollTop /*|| window.pageYOffset*/
  // 平滑滚动,时长500ms,每10ms一跳,共50跳
  let step = 10;
  if (total > distance) {
    let newTotal = total - distance;
    step = newTotal / 50;
    smoothDown()
  } else {
    let newTotal = distance - total;
    step = newTotal / 50
    smoothUp()
  }
  function smoothDown () {
    if (distance < total) {
      distance += step
      document.body.scrollTop = distance
      document.documentElement.scrollTop = distance
      window.pageYOffset = distance
      setTimeout(smoothDown, 10)
    } else {
      document.body.scrollTop = total
      document.documentElement.scrollTop = total
      window.pageYOffset = total
    }
  }
  function smoothUp () {
    if (distance > total) {
      distance -= step
      document.body.scrollTop = distance
      document.documentElement.scrollTop = distance
      window.pageYOffset = distance
      setTimeout(smoothUp, 10)
    } else {
      document.body.scrollTop = total
      document.documentElement.scrollTop = total
      window.pageYOffset = total
    }
  }
}

export function arrayScroll(className,num=0,color='blue') {
  //页面滚动了的距离
  let flag = 0;
  let jump = document.querySelectorAll(className)
  let height = document.documentElement.scrollTop || document.body.scrollTop /*|| window.pageYOffset*/
  jump.forEach((j,index)=>{
    let total = j.offsetTop+num
    // j.style.color=''
    if(index===0 && height<total){
      flag = index
      // j.style.color=color
    }else
    if(index===jump.length-1 && height>total){
      flag = index
      // j.style.color=color
    }else if(index>0 && index<jump.length && jump[index-1].offsetTop+num < height && total > height){
      flag = index
      // j.style.color=color
    }
  })
  return flag;
}

原理:
通过document.querySelectorAll(’.item-title’)获取到元素(item-title名字可根据实际需求进行变动),然后获取到元素的offsetTop,滚动到对应的位置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值