vue监听页面中的某个div的滚动事件,并判断滚动的位置

在开发中常常会遇到这样一个vue页面,页面分为左右两部分,左边是目录树,右边是一个类名为xq-box的div,在xq-box中多个div上下并列布局,每个div中的内容就对应着左边目录树中的相应节点,现在的目标是,要监听这个xq-box滚动事件,右边一旦开始滚动,就要知道滚动到哪个子div,并让左边的目录树中对应的节点高亮显示。要怎么做呢?

1、首先,先写好大概的页面布局,这里要注意,右边xq-box的子div要绑定"'xqItem'+序号"的id,为了下面用js能获取到匹配的dom元素:

<template>
    <div class="container">
        <div class="left-box">
          <div class="menu-box">
            <div class="menu-title">
              <p>目录</p>
            </div>
            <div
              class="menu-item"
              v-for="(menu, index) in menuList"
              :key="index"
              :class="{ 'active': menuActive === index }"
              @click="chooseMenu(menu.name, index)"
            >
              <img :src="menu.icon" class="menu-icon" />
              <p>{{ menu.name }}</p>
            </div>
          </div>
        </div>
        <div class="right-box">
          <div class="xq-box" ref="xqBox">
            <div
                class="xq-item"
                :id="'xqItem' + index"
                v-for="(item, index) in xqConList"
                :key="index"
              >
                 <!--这里渲染出目录内容-->
                 <div class="xq-item-name">
                    {{ item.name }}
                  </div>
                  <div class="xq-item-con">
                    {{ item.content }}
                  </div>
              </div>
          </div>
        </div>
    </div>
</template>

2、然后,在css里给xq-box高度,设置其超出能滚动:

<style lang="stylus" scoped>
  .right-box
      height 600px
      .xq-box
          height 100%
          overflow-y auto
<style>

3、接着,在计算属性获取到这个ref="xqBox"的dom元素,写一个函数handleScroll()获取滚动距离并判断滚动到哪两个子div之间,并在页面渲染完后监听这个xq-box的滚动事件。

export default {
  name: "menuList",
  data() {
    return {
      menuActive: 0,  //左侧高亮的item
      menuList: [],  //左侧目录树
      xqConList: []  //右侧目录内容列表
    }
  },
  computed: {
    xqBox() {
      return this.$refs.xqBox;
    }
  },
  mounted() {
    this.$nextTick(() => {
      // //监听这个dom的scroll事件
      // this.xqBox.onscroll = () => {
      //   console.log("on scroll");
      //   this.handleScroll();
      // };
      //监听这个dom的scroll事件
      this.xqBox.addEventListener("scroll", this.handleScroll);
    });
  },
  methods: {
    handleScroll() {
      //获取dom滚动距离
      const scrollTop = this.xqBox.scrollTop;
      //获取可视区高度
      const offsetHeight = this.xqBox.offsetHeight;
      //获取滚动条总高度
      const scrollHeight = this.xqBox.scrollHeight;
      //xqConList 为目录内容列表
      for (let i = 0; i < this.xqConList.length - 1; i++) {
        //offsetTop: 获取当前元素到其定位父级(offsetParent)的顶部距离
        let offset_before = this.$el.querySelector("#xqItem" + i).offsetTop;
        let offset_after = this.$el.querySelector("#xqItem" + (i + 1))
          .offsetTop;

        //根据xqItem离顶部距离判断滚动距离落在哪两个item之间
        if (scrollTop >= offset_before && scrollTop < offset_after) {
          // console.log("offset", offset_before, offset_after, scrollTop);
          // console.log("scrollHeight", scrollTop, offsetHeight, scrollHeight);
          //判断是否滚动到了底部
          if (scrollTop + offsetHeight >= scrollHeight) {
            // 把距离顶部的距离加上可视区域的高度 等于或者大于滚动条的总高度就是到达底部
            // console.log("已滚动到底部");
            if (this.menuActive < i) {
              this.menuActive = i;
            }
          } else {
            this.menuActive = i;
          }
          break;
        }
      }
    },
  }
};

经查询得知,Vue组件在patch阶段结束时会把this.$el赋值为挂载的根dom元素,我们可以直接使用$el的querySelector, querySelectorAll等方法获取匹配的元素。因1中每个内容块子div已经绑定id,所以此处可以用 this.$el.querySelector("#xqItem" + i) 获取到每个子div。

还有一个要注意的是,这里之所以要判断是否滚动到了底部,是因为xq-box一旦滚动到底部,就可以看到最后几个目录对应的子div,此时的滚动距离scrollTop只会落在这最后几个子div的第一个子div(序号即当前本次循环中的i)的离顶部距离位置上,这个时候如果左侧目录树高亮的正好是这最后几个目录的其中任意一个,则无需更改高亮;但是如果此时 this.menuActive 的值还比最后几个子div中的第一个的序号要小,即比本次循环的 i 要小,则需要更改为当前的 i 值。

4、如果要点击左边目录树,右边xq-box也要自动滚动到相应的目录内容,则要增加以下方法:

chooseMenu(name, index) {
      this.menuActive = index;
      // //可以用scrollIntoView
      // document.querySelector("#xqItem" + index).scrollIntoView({
      //   block: "start",
      //   behavior: "smooth"
      // });
      let offsetTop = this.$el.querySelector("#xqItem" + index).offsetTop;
      console.log("#xqItem" + index + " offsetTop: " + offsetTop);
      this.xqBox.scrollTop = this.$el.querySelector(
        "#xqItem" + index
      ).offsetTop;
},

这样,“监听这个xq-box滚动事件,右边一旦开始滚动,就要知道滚动到哪个子div,并让左边的目录树中对应的节点高亮显示”这个功能便实现了。

(0)

相关推荐

  • vue监听页面中的某个div的滚动事件并判断滚动的位置

    在开发中常常会遇到这样一个vue页面,页面分为左右两部分,左边是目录树,右边是一个类名为xq-box的div,在xq-box中多个div上下并列布局,每个div中的内容就对应着左边目录树中的相应节点,现在的目标是,要监听这个xq-box滚动事件,右边一旦开始滚动,就要知道滚动到哪个子div,并让左边的目录树中对应的节点高亮显示.要怎么做呢? 1.首先,先写好大概的页面布局,这里要注意,右边xq-box的子div要绑定"'xqItem'+序号"的id,为了下面用js能获取到匹配的dom元

  • vue监听页面中的某个div的滚动事件,并判断滚动的位置

    在开发中常常会遇到这样一个vue页面,页面分为左右两部分,左边是目录树,右边是一个类名为xq-box的div,在xq-box中多个div上下并列布局,每个div中的内容就对应着左边目录树中的相应节点,现在的目标是,要监听这个xq-box滚动事件,右边一旦开始滚动,就要知道滚动到哪个子div,并让左边的目录树中对应的节点高亮显示.要怎么做呢? 1.首先,先写好大概的页面布局,这里要注意,右边xq-box的子div要绑定"'xqItem'+序号"的id,为了下面用js能获取到匹配的dom元

  • Vue监听页面刷新和关闭功能

    我在做项目的时候,有一个需求,在离开(跳转或者关闭)购物车页面或者刷新购物车页面的时候向服务器提交一次购物车商品数量的变化. 将提交的一步操作放到 beforeDestroy 钩子函数中. beforeDestroy() { console.log('销毁组件') this.finalCart()}, 但是发现  beforeDestroy 只能监听到页面间的跳转,无法监听到页面刷新和关闭标签页. 所以还是要借助 onbeforeunload 事件. 顺便复习了一下 JavaScript 中的一

  • vue监听页面滚动到某个高度触发事件流程

    目录 监听页面滚动到某个高度触发事件 动态监听页面滚动高度 监听页面滚动到某个高度触发事件 methods: {    showIcon() {       if (         !!document.documentElement.scrollTop &&         document.documentElement.scrollTop > 200        ) {                         页面高度大于200执行操作         } else

  • vue 监听窗口变化对页面部分元素重新渲染操作

    问题 在处理页面重新渲染时通常的做法是: 用vue-router重新路由到当前页面,页面是不进行刷新的 采用window.reload(),或者router.go(0)刷新时,整个浏览器进行了重新加载,闪烁,体验不好 使用 v-if 重新渲染部分组件或容器 需要重新渲染的内容 <div v-if="render"> ... </div> vue 监听窗口大小发生改变 使用 window.addEventListener() 添加 resize 事件监听窗口变化

  • vue如何监听页面的滚动的开始和结束

    目录 监听页面的滚动的开始和结束 vue监听页面滚动事件 方法:监听滚动实现 问题:监听不到页面的滚动 监听页面的滚动的开始和结束 export default { data() { return { oldScrollTop: 0, //记录上一次滚动结束后的滚动距离 scrollTop: 0 // 记录当前的滚动距离 } }, watch: { scrollTop(newValue, oldValue) { setTimeout(() => { if(newValue == window.s

  • 小程序中监听页面滚动的几种方法实例

    目录 目录 实现效果 下面是Intersection Observer在MDN上的介绍 IntersectionObserver relativeToViewport 接受参数 Object margins observe(string targetSelector, function callback) 参数 Object res 小程序中监听页面的其他方法 page-meta scroll-view 总结 在工作中我们经常遇到需要监听页面中元素位置,当元素超出显示区域或即将显示到页面上,我们

  • vue如何监听页面缓存事件

    目录 监听页面缓存事件 事情的起因是这样的 监听缓存事件代码 在main创建缓存事件 在组件生命周期中 在组件业务代码 监听页面缓存事件 事情的起因是这样的 项目中需要用到websocket,在网页刚打开的时候,就要进行对话的连接绑定,就我这菜鸟来说,第一次这么搞事情,也是刚接触websocket没多久,这咋整啊?在App.vue中设置了绑定,所有的信息返回都在app.vue组件里面,但是其他组件怎么去获取?而且需要缓存到本地.而当初我还没接触vuex,所以在其他组件里面获取服务器返回的信息只能

  • vue 监听某个div垂直滚动条下拉到底部的方法

    如下所示: this.$nextTick(() => { const el = document.querySelector('.act-not'); const offsetHeight = el.offsetHeight; el.onscroll = () => { const scrollTop = el.scrollTop; const scrollHeight = el.scrollHeight; if ((offsetHeight + scrollTop) - scrollHeig

  • vue中watch监听对象中某个属性的方法

    目录 immediate 和 handler deep 深度监听 以currentParams为例,监听selOrgId属性 immediate 和 handler watch 的用法有个特点,就是当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行.如果我们需要在最初绑定值得时候也执行函数,就需要用到 immediate 属性. 'currentParams.selOrgId': { handler(newV, oldV) { console.log("watch", ne

随机推荐