vue给某元素设置滚动到底部触发事件(给元素添加overflow:scroll时的问题)

本文介绍了一个Vue项目的实现细节,特别是如何在元素滚动到底部时触发加载更多数据的功能,同时展示了如何使用Vue的生命周期钩子和事件监听来实现这一功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在vue中如果你给某元素设置overflow:auot或者overflow:scroll时这样可以让超出可视区的内容可以滚动
但是如果这个时候在给让设置滚动到底部触发事件会有问题那就是只要你滚动就是立即触发这个事件
所以基于这点我改了一下代码效果不错
直接上代码

<template>
  <div class="list">
    <div class="header">
      <img src="/static/img/1_01.jpg" alt="">
    </div>
    <div class="main">
      <div class="left">
        <ul>
           <li v-for="(e,i) in left" :key="i" @click="save(e.id)" :class="active==e.id?'active':''">
             <span>{{e.title}}</span>
           </li>
        </ul>
      </div>
      <div class="right" @scroll="scrollEvent">
        <div class="banner">
          <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
            <van-swipe-item><img src="/static/img/img_20.gif" alt=""></van-swipe-item>
            <van-swipe-item><img src="/static/img/img_20.gif" alt=""></van-swipe-item>
            <van-swipe-item><img src="/static/img/img_20.gif" alt=""></van-swipe-item>
            <van-swipe-item><img src="/static/img/img_20.gif" alt=""></van-swipe-item>
          </van-swipe>
        </div>
        <ul>
          <li v-for="(e,i) in list" :key="i">
            <img :src="e.img" alt="">
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data()
  {
    return{
      left:[],
      list:[],
      active:0
    }
  },
  methods:{
    scrollEvent(e){
        if(e.srcElement.scrollTop+e.srcElement.offsetHeight>e.srcElement.scrollHeight-100){ 
          console.log("啦啦啦啦啦触发了") 
          this.active=this.active+1;
          //加载更多
        }

      },
    save(id)
    {
      //this.list=[];
      this.active=id; 
    }
  },
  mounted()
  {
    this.$axios.get("/static/data.json").then((res)=>{
      this.left=res.data.left
    })

      this.list=[];
      this.$axios.get("/static/data.json").then((res)=>{
        res.data.list.forEach((e)=>{
          if(e.pid==this.active)
          {
            this.list.push(e)
          }
        })
      })

  },
  watch:{
    active(val)
    {
      this.list=[];
      this.$axios.get("/static/data.json").then((res)=>{
        res.data.list.forEach((e)=>{
          if(e.pid==val)
          {
            this.list.push(e)
          }
        })
      })
    } 
  }
}
</script>

<style lang="scss" scoped>
.active{
  background: white;
  border-left: 2px solid red;
}
.list{
  width: 100%;
  height: 100%;
}
.header{
  width: 100%;
  position: fixed;
  top: 0;
  left: 0;
  img{
    width: 100%;
  }
}
.main{
  width: 100%;
  height: 100%;
  margin-top: 1.05rem;
  display: flex;
  .left{
    width: 30%;
    height: 100%;
    background: #f2f2f2;
    padding-bottom: 2rem;
    position: fixed;
    left: 0;
    overflow: auto;
    ul{
      width: 100%;
      li{
        width: 100%;
        line-height: 0.8rem;
        text-align: center;
      }
    }
  }
  .right{
    width: 70%;
    height: 100%;
    padding:0px 20px;
    padding-bottom: 1.8rem;
    position: fixed;
    right: 0;
    overflow: auto;
    .banner{
      width: 100%;
      img{
       width: 100%;
        height: 1.8rem;
      }
    }
    ul{
      width: 100%;
      li{
        width: 100%;
        img{
          width: 100%;
        height:1200px;
        }
      }
    }
  }
  .left::-webkit-scrollbar{
    display: none;
   }  //让出现的滚动条隐藏
  .right::-webkit-scrollbar{
    display: none;
   }
}
</style>

整理一下

<template>
  <div class="box" @scroll="scrollEvent">
    <ul>
	<li></li>
	……
	<li></li>
    </ul>
  </div>
<template>
export default {
    name: 'demo',
    data () {
      return {
        msg: '',
      }
    },
    methods: {
      scrollEvent(e){
        console.log(e)
      },
    }
}

.box{
    position: fixed;
    left: 0;
    overflow: auto
}

export default {
    name: 'demo',
    data () {
      return {
        msg: '',
      }
    },
    methods: {
      scroll(e){
        //滚动的像素+容器的高度>可滚动的总高度-100像素
        if(e.srcElement.scrollTop+e.srcElement.offsetHeight>e.srcElement.scrollHeight-100){ 
          this.loadMore();    //加载更多
        }
      },
    }
}
methods: {
      scroll(e){
        // !this.moreLoading 没有在加载状态,触发加载更多时,把this.moreLoading置未true
        // !this.noMore 没有更多的状态为false,当我们取到的数据长度小于1页的数量时,就没有更多了数据了,把 this.noMore置为true,这样就不会触发无意义的加载更多了
        if(e.srcElement.scrollTop+e.srcElement.offsetHeight>e.srcElement.scrollHeight-100 && !this.moreLoading && !this.noMore){
          this.loadMore();
        }
      },
    }

以上优点小bug更改一下


<template>
  <div class="list">
    <div class="header">
      <img src="/static/img/1_01.jpg" alt="">
    </div>
    <div class="main">
      <div class="left">
        <ul>
           <li v-for="(e,i) in left" :key="i" @click="save(e.id)" :class="active==e.id?'active':''">
             <span>{{e.title}}</span>
           </li>
        </ul>
      </div>
      <div class="right" @scroll="scrollEvent">
        <div class="banner">
          <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
            <van-swipe-item><img src="/static/img/img_20.gif" alt=""></van-swipe-item>
            <van-swipe-item><img src="/static/img/img_20.gif" alt=""></van-swipe-item>
            <van-swipe-item><img src="/static/img/img_20.gif" alt=""></van-swipe-item>
            <van-swipe-item><img src="/static/img/img_20.gif" alt=""></van-swipe-item>
          </van-swipe>
        </div>
        <ul>
          <li v-for="(e,i) in list" :key="i">
            <img :src="e" alt="">
          </li>
        </ul>
        <van-loading type="spinner" color="#1989fa" v-show="loading"/>
      </div>
    </div>
 
  </div>
</template>

<script>
export default {
  data()
  {
    return{
      left:[],
      list:[],
      active:0,
      loading:false,
    }
  },
  methods:{
    scrollEvent(e){
        //console.log(e)
         let scrollTop = e.srcElement.scrollTop
            let clientHeight = e.srcElement.offsetHeight
            let scrollHeight = e.srcElement.scrollHeight
            if (scrollTop + clientHeight >= scrollHeight) { // 滚动到底部,逻辑代码
            setTimeout(()=>{
               this.loading=true
            console.log(111)
            this.active=this.active+1
            if(this.active>=this.left.length)
            {
              this.active=0;
            }
            },1500)
        }
      },
    // scrollEvent(e){
    //   this.loading=true
    //    setTimeout(()=>{
    //      //scrollTop + clientHeight >= scrollHeight
    //      //console.log(e)
    //      this.loading=false
    //     if(e.srcElement.scrollTop+e.srcElement.offsetHeight>e.srcElement.scrollHeight-100 && !this.loading){ 
    //       console.log("啦啦啦啦啦触发了") 
         
    //         this.active++;
    //         if(this.active>this.left.length)
    //         {
    //           this.active=0
    //         }
        
    //       //加载更多
    //     }
    //       },3000)

    //   },
    save(id)
    {
      //this.list=[];
      this.active=id; 
    }
  },
  mounted()
  {
    window.addEventListener('scroll', this.scrollEvent)
    this.$axios.get("/static/data.json").then((res)=>{
      this.left=res.data.left
    })

      this.list=[];
      this.$axios.get("/static/data.json").then((res)=>{
        res.data.list.forEach((e)=>{
          if(e.pid==this.active)
          {
            this.list=e.img
          }
        })
      })

  },
  watch:{
    active(val)
    {
      this.list=[];
      this.$axios.get("/static/data.json").then((res)=>{
        res.data.list.forEach((e)=>{
          if(e.pid==val)
          {
            this.list=e.img
          }
        })
      })
    } 
  }
}
</script>

<style lang="scss" scoped>
.active{
  background: white;
  border-left: 2px solid red;
}
.list{
  width: 100%;
  height: 100%;
}
.header{
  width: 100%;
  position: fixed;
  top: 0;
  left: 0;
  img{
    width: 100%;
  }
}
.main{
  width: 100%;
  height: 100%;
  margin-top: 1.05rem;
  display: flex;
  .left{
    width: 30%;
    height: 100%;
    background: #f2f2f2;
    padding-bottom: 2rem;
    position: fixed;
    left: 0;
    overflow: auto;
    ul{
      width: 100%;
      li{
        width: 100%;
        line-height: 0.8rem;
        text-align: center;
      }
    }
  }
  .right{
    width: 70%;
    height: 100%;
    padding:0px 20px;
    padding-bottom: 1.8rem;
    position: fixed;
    right: 0;
    overflow: auto;
    .banner{
      width: 100%;
      img{
       width: 100%;
        height: 1.8rem;
      }
    }
    ul{
      width: 100%;
      li{
        width: 100%;
        img{
          width: 100%;
        }
      }
    }
  }
  .left::-webkit-scrollbar{
    display: none;
   }  //让出现的滚动条隐藏
  .right::-webkit-scrollbar{
    display: none;
   }
}
</style>
<think>嗯,用户想了解在Vue3中如何设置元素scrollTop值。首先,我需要回忆一下Vue3的基本操作方式,特别是在处理DOM元素的注意事项。Vue3推荐使用模板引用(template refs)来直接访问DOM元素,这可能是一个关键点。 用户提到的是scroll事件设置scrollTop的值。scroll事件通常用于监听元素滚动位置变化,而设置scrollTop则是要控制滚动的位置。可能需要分步骤来讲解:如何获取元素引用,如何监听scroll事件,以及如何通过ref来修改scrollTop的值。 首先,在模板中,需要使用ref属性来标记元素,比如给div添加ref="scrollContainer"。然后在setup函数或者script setup中使用这个ref。记得在onMounted生命周期钩子中确保元素已经渲染完毕,否则可能获取不到DOM节点。 接下来,监听scroll事件,可以使用@scroll或者v-on:scroll来绑定事件处理函数。在处理函数中,可能需要访问scrollTop的值,或者进行一些操作,比如限制滚动位置。 然后是关于设置scrollTop的值。直接修改element.scrollTop属性应该是最直接的方法,但需要注意可能的响应性问题。不过因为scrollTop是DOM属性,直接修改它不会触发Vue的响应式系统,所以应该没有问题。但需要确保在DOM元素已经正确挂载后再进行操作,否则会报错。 可能还需要考虑一些常见问题,比如为什么设置scrollTop但页面没有滚动。这候需要检查是否正确获取了DOM元素,或者是否有CSS样式导致滚动条不存在,比如overflow设置是否正确。另外,如果是在异步操作中设置scrollTop,可能需要使用nextTick来确保DOM更新完成。 用户可能的应用场景包括滚动到特定位置,或者恢复滚动位置等。比如,在聊天应用中,收到新消息后自动滚动底部。这候可能需要同操作scrollTop和scrollHeight。 还需要注意,直接操作DOM可能与Vue的数据驱动理念有些冲突,但在需要精确控制滚动行为,这是必要的。同,在组合式API中,使用ref和生命周期钩子的方式更为简洁。 最后,可能需要提供一个完整的示例代码,展示从模板到脚本的完整实现,帮助用户更好地理解。同,提醒用户注意生命周期钩子的使用和可能的错误情况,比如在元素未挂载访问ref的情况。</think>在 Vue3 中操作元素scrollTop 值可以通过以下步骤实现: 1. **模板中使用 ref 标记元素**: ```html <template> <div ref="scrollContainer" @scroll="handleScroll"> <!-- 长内容 --> </div> </template> ``` 2. **组合式 API 实现**: ```javascript <script setup> import { ref, onMounted } from 'vue' const scrollContainer = ref(null) // 设置 scrollTop const setScrollPosition = (position) => { if (scrollContainer.value) { scrollContainer.value.scrollTop = position } } // 监听滚动事件 const handleScroll = (e) => { console.log('当前滚动位置:', e.target.scrollTop) } // 确保元素已挂载后操作 onMounted(() => { // 初始化滚动位置 setScrollPosition(0) }) </script> ``` **注意事项**: 1. **CSS 要求**: ```css /* 必须设置 overflow 才能产生滚动 */ .scroll-container { height: 300px; overflow-y: auto; } ``` 2. **常见问题排查**: - 确保元素已正确挂载(使用 `onMounted` 生命周期) - 检查 CSS 的 `overflow` 属性是否生效 - 异步操作使用 `nextTick`: ```javascript import { nextTick } from 'vue' nextTick(() => { setScrollPosition(100) }) ``` 3. **滚动到指定位置示例**: ```javascript // 滚动底部 const scrollToBottom = () => { if (scrollContainer.value) { scrollContainer.value.scrollTop = scrollContainer.value.scrollHeight } } // 滚动到指定元素 const scrollToElement = (selector) => { const element = scrollContainer.value.querySelector(selector) if (element) { element.scrollIntoView({ behavior: 'smooth' }) } } ``` **为什么直接修改 scrollTop 有效?** - `scrollTop` 是 DOM 元素的固有属性 - Vue3 的 ref 系统允许直接访问原生 DOM 元素 - 修改不会触发 Vue 的响应式更新(纯 DOM 操作) **最佳实践**: 1. 封装为可复用函数 2. 结合滚动事件记录位置 3. 需要平滑滚动可使用 `scrollTo` 方法: ```javascript scrollContainer.value.scrollTo({ top: 200, behavior: 'smooth' }) ``` **完整示例**: ```html <template> <div ref="scrollBox" class="scroll-box" @scroll="handleScroll"> <div v-for="n in 100" :key="n">Item {{ n }}</div> <button @click="scrollTo(500)">跳转到500px</button> <button @click="scrollToBottom">到底部</button> </div> </template> <script setup> import { ref } from 'vue' const scrollBox = ref(null) const scrollTo = (position) => { if (scrollBox.value) { scrollBox.value.scrollTo({ top: position, behavior: 'smooth' }) } } const scrollToBottom = () => { if (scrollBox.value) { scrollBox.value.scrollTop = scrollBox.value.scrollHeight } } const handleScroll = (e) => { console.log('当前滚动位置:', e.target.scrollTop) } </script> <style> .scroll-box { height: 300px; overflow-y: auto; border: 1px solid #ccc; padding: 20px; } </style> ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值