+
99
-

回答

800_auto

我写了一个更丝滑的上滑加载更多消息列表代码:

点击查看完整源码

<template>
  <view class="container">
    <scroll-view 
      class="scroll-view"
      scroll-y 
      @scrolltoupper="onScrollToUpper"
      :scroll-top="scrollTop"
      :scroll-with-animation="false"
      :refresher-enabled="false"
      upper-threshold="150"
      style="height: 100vh;"
    >
      <view class="loading" v-if="isLoading">加载中...</view>
      <view 
        v-for="(message, index) in messages" 
        :key="message.id" 
        class="message-item"
      >
        {{ message.content }}
      </view>
    </scroll-view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      messages: [],
      scrollTop: 0,
      isLoading: false,
      messageId: 0 // 用于生成唯一ID
    }
  },
  
  mounted() {
    this.loadInitialMessages()
  },

  methods: {
    async loadInitialMessages() {
      const initialMessages = await this.fetchMessages(20)
      this.messages = initialMessages
      this.$nextTick(() => {
        this.scrollToBottom()
      })
    },

    scrollToBottom() {
      // 延迟执行以确保DOM已更新
      setTimeout(() => {
        const query = uni.createSelectorQuery().in(this)
        query.select('.scroll-view').boundingClientRect(data => {
          this.scrollTop = data.height * 2
        }).exec()
      }, 100)
    },

    async onScrollToUpper() {
      if (this.isLoading) return
      
      // 获取当前滚动位置和内容高度
      const query = uni.createSelectorQuery().in(this)
      query.select('.scroll-view').boundingClientRect(async rect => {
        const oldHeight = rect.height
        const oldScrollTop = this.scrollTop

        this.isLoading = true
		console.log("加载更多")
        const newMessages = await this.fetchMessages(10)
        
        // 将新消息添加到顶部
        this.messages = [...newMessages, ...this.messages]

        // 等待DOM更新
        this.$nextTick(() => {
          query.select('.scroll-view').boundingClientRect(newRect => {
            const newHeight = newRect.height
            const heightDiff = newHeight - oldHeight
            
            // 调整滚动位置,保持视觉位置不变
            this.scrollTop = oldScrollTop + heightDiff
            this.isLoading = false
          }).exec()
        })
      }).exec()
    },

    async fetchMessages(count) {
      // 模拟API请求
      return new Promise(resolve => {
        setTimeout(() => {
          const messages = Array.from({ length: count }, () => ({
            id: this.messageId++,
            content: `历史消息 ${this.messageId}`
          }))
          resolve(messages)
        }, 1000)
      })
    }
  }
}
</script>

<style>
.container {
  height: 100vh;
}

.scroll-view {
  padding: 20px;
  box-sizing: border-box;
}

.message-item {
  padding: 10px;
  margin: 10px 0;
  background: #f5f5f5;
  border-radius: 5px;
  min-height: 40px;
}

.loading {
  text-align: center;
  padding: 10px;
  color: #999;
}
</style>

网友回复

我知道答案,我要回答