Vue监听滚动实现锚点定位(双向)

这里很感谢 http://www.jb51.net/article/110325.htm 这篇文章带来的启发

但是我和他不同,网上的方法都是  这样计算滚动条距离窗口顶部的距离,注意是窗口,用的是document对象

 

 // Chrome
 document.body.scrollTop
 // Firefox
 document.documentElement.scrollTop
 // Safari
 window.pageYOffset

我这项目就无法正常这样使用了,首先我们vue项目有个总页面layout组件,左侧分 menu组件,最上方fixed了两块div,最后加上content页面内容给用户看的主界面,所有的页面都是这样渲染进layout__content里的 这就导致无法使用document对象来获取滚动条高度

具体的效果如图:

我调试发现,页面在某一块 上有css,滚动条就在这上面,所以,我这里使用的@scroll方法,

注意是@scroll 而不是scroll.native,

  handleScroll (el) {
        this.scrollTop = this.$refs.content.scrollTop
      },

 

 this.$refs.content.scrollTop 打印出来就是滚动条距离页面的距离

 

scrollTop  这个data属性,我通过props将其传到了子组件zhong,通过页面共同的入口router-view导入

当然这就将这个属性,所有页面都能接收到了,感觉不是很好,暂且先这样实现

回到我本身的展示页面,子组件 监听scrollTop

 

props: ['scrollTop'],
watch: {
  scrollTop (val) {
    this.onScroll()
    this.pageTop = val
  }
},
这里的pageTop 我这里做了一下赋值,因为尽量别直接在子组件改变props的值
created () {
  this.$nextTick(() => {
    this.pageTop = this.scrollTop
  })
},
 
onScroll () {
  let _article = document.querySelectorAll('.step-jump')
  _article.forEach((item, index) => {
    if (this.scrollTop >= item.offsetTop) {
      this.activeStep = index
    }
  })
},

监听鼠标滚动事件,这样就可以实现了,当然我的页面html是这样的情况,以各个小组件拼接起来,夹杂着用来定位的相同class的div元素

 

现在来看一下step元素,如果你需要用到自定义的icon,需要加上这个属性,源码通过是否传入这个来判断是 icon 还是 text


  
    
  

点击事件方法 jump

 

  jump (index) {
        let that = this
        this.activeStep = index
        // 用 class="step-jump" 添加锚点
        let jump = document.querySelectorAll('.step-jump')
        let total = jump[index].offsetTop
        console.log('纵坐标', total)
//        this.$emit('viewScroll', total)
        let distance = this.pageTop
//         平滑滚动,时长500ms,每10ms一跳,共50跳
        let step = total / 50 >> 0
        console.log(step, '222')
        if (total > distance) {
          smoothDown()
        } else {
          let newTotal = distance - total
          step = newTotal / 50 >> 0
          smoothUp()
        }
        function smoothDown () {
          if (distance < total) {
            distance += step
            that.$emit('viewScroll', distance)
            setTimeout(smoothDown, 10)
          } else {
            that.$emit('viewScroll', total)
          }
        }
        function smoothUp () {
          if (distance > total) {
            distance -= step
            that.$emit('viewScroll', distance)
            setTimeout(smoothUp, 10)
          } else {
            that.$emit('viewScroll', total)
          }
        }
      },

这里就是借鉴了网友的想法,每一小段一小段的跳,这样会导致视觉上是一个平滑的效果,而不是我点击了就突然scrollTop就突然下去或者上来,避免了很突兀的感觉。

有什么问题或建议,请直接提出来,谢谢哟

完善一下上面的代码,将多次emit事件删除,直接写入到父组件中!!!来判断

!!!!  其实上面这种实现还是有很大水分的,如果滚动条是相对于浏览器窗口的,其实直接document对象 判断scrollTop即可,另写一篇文章来重新书写vue scroll平滑滚动!最新的优化 可以看这个  ==========>>>>>>

https://blog.csdn.net/shentibeitaokong/article/details/81349819

你可能感兴趣的:(Vue监听滚动实现锚点定位(双向))