web聊天框丝滑滚动到最底部解决方案

540 阅读2分钟

转载需注明出处

问题描述

graph TD
首次进入界面 --> 有聊天数据-->滑动到最低部
首次进入界面 --> 无聊天数据--> 滑动到最低部-->聊天中-->用户未滚动鼠标-->自动滑动开启
聊天中-->用户滚动鼠标-->滚动到最底部-->自动滚动开启
用户滚动鼠标-->未滚动到最底部-->禁止自动滑动

实现思路

  1. scrollIntoview可以将dom滑动到可视区域
  2. 聊天框每次移动到最底部,可以看作将最底部的一个div设置为可视区域最底端

解决办法

1. 开启界面

对于刚进入界面来说,直接滑动最底部

<template>
  <div>
    <div class="content">
      <!-- 这里放置你的内容 -->
      <p v-for="item in 100" :key="item">{{ item }}</p>
      <div ref="bottomDivRef"></div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue';

const bottomDivRef = ref(null);

const scrollToBottom = () => {
   // 确保 DOM 更新后再执行滚动
 nextTick(() => {
    if (bottomDivRef.value) {
      bottomDivRef.value.scrollIntoView({
        behavior: 'smooth',
        block: 'end'
      });
    }
  });
};

// 如果需要在组件加载完成后自动滚动到最底部,可以这样做:
onMounted(() => {
  scrollToBottom();
});

</script>

<style scoped>
.content {
  height: 200px; /* 或者其他的固定高度 */
  overflow-y: auto;
  background: red;
}
</style>

2. 开始聊天

如果在用户聊天中需自动滚动到底部

<template>
  <div>
    <div class="content">
      <!-- 这里放置你的内容 -->
      <p v-for="item in items" :key="item">{{ item }}</p>
      <div ref="bottomDivRef"></div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue';

const items = ref([]);
const bottomDivRef = ref(null);

// 模拟用户请求数据
const fetchMoreData = () => {
  setTimeout(() => {
    const newItems = Array.from({ length: 10 }, (_, index) => 100 + index +  items.value.length);
    items.value.push(...newItems);
    scrollToBottom();
  }, 2000);
};

const scrollToBottom = () => {
  nextTick(() => {
    if (bottomDivRef.value) {
      bottomDivRef.value.scrollIntoView({
        behavior: 'smooth',
        block: 'end'
      });
    }
  });
};

// 初始化时滚动到底部
onMounted(() => {
  scrollToBottom();
});

// 模拟每隔一段时间获取更多数据
onMounted(() => {
  setInterval(fetchMoreData, 3000); // 每5秒获取一次
});

</script>

<style scoped>
.content {
  height: 200px; /* 或者其他的固定高度 */
  overflow-y: auto;
  background: red;
}
</style>

3. 滚动鼠标

如果聊天中用户翻滚了鼠标,鼠标如果滚动到界面最底部,则自动滑动开启。否则禁止界面自动滑动,以用户鼠标翻滚的地方为准(这里我们使用vueuse的useScroll)

<template>
  <div>
    <div ref="el" class="content">
      <!-- 这里放置你的内容 -->
      <p v-for="item in items" :key="item">{{ item }}</p>
      <div ref="bottomDivRef"></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue';
import { useScroll } from '@vueuse/core';

const items = ref([]);
const el = ref(null);
const bottomDivRef = ref(null);

const { isScrolling, arrivedState } = useScroll(el, { behavior: 'smooth' });

const fetchMoreData = () => {
  setTimeout(() => {
    const newItems = Array.from({ length: 20 }, (_, index) => 1 + index + items.value.length);
    items.value.push(...newItems);
    // 如果没移动,且在最底部,则继续滚动
    if (!isScrolling.value && arrivedState.bottom) {
      scrollToBottom();
    }
  }, 2000);
};

const scrollToBottom = () => {
  nextTick(() => {
    if (bottomDivRef.value) {
      bottomDivRef.value.scrollIntoView({
        behavior: 'smooth',
        block: 'end',
      });
    }
  });
};

// 初始化时滚动到底部
onMounted(() => {
  scrollToBottom();
  // 模拟每隔一段时间获取更多数据
  setInterval(fetchMoreData, 3000); // 每5秒获取一次
});
</script>

<style scoped lang="scss">
.content {
  height: 500px; /* 或者其他的固定高度 */
  overflow-y: auto;
  background: red;
}
</style>