Vue 聊天列表滚动方案

目前只实现了自动滚动到底部。还未实现下拉加载更多。如果需要在滚动触顶时加载更多,同时保持滚动位置,可能需要更加复杂的方案。

  1. 初始化时自动滚动到底部。
  2. 当列表内容变化时,如果用户当前位置接近底部且未向上滚动,则自动滚动到底部。
  3. 如果用户正在浏览上方内容,则保持当前滚动位置。
typescript 复制代码
import { useResizeObserver, useScroll, whenever } from "@vueuse/core";

export type MaybeHTMLElement = MaybeRefOrGetter<HTMLElement | null | undefined>;
/**
 * 聊天滚动组合函数
 * @param options - 配置选项
 * @param options.scrollTarget - 滚动容器元素
 * @param options.listElement - 列表内容元素,用于监听尺寸变化
 * @returns 包含滚动到底部方法的对象
 * @remarks
 * 该函数提供智能滚动行为:
 * 1. 初始化时自动滚动到底部
 * 2. 当列表内容变化时,如果用户当前位置接近底部且未向上滚动,则自动滚动到底部
 * 3. 如果用户正在浏览上方内容,则保持当前滚动位置
 */
export const useChatScroll = (options: {
  scrollTarget: MaybeHTMLElement;
  listElement: MaybeHTMLElement;
}) => {
  const scrollTarget = computed(() => toValue(options.scrollTarget));
  const { directions } = useScroll(scrollTarget);
  /**
   * 滚动到底部
   * @param options - 滚动选项
   * @param options.behavior - 滚动行为,"auto" 为瞬间滚动,"smooth" 为平滑滚动
   */
  const scrollToBottom = (options?: { behavior?: "auto" | "smooth" }) => {
    if (!scrollTarget.value) return;
    scrollTarget.value.scrollTo({
      top: scrollTarget.value.scrollHeight,
      behavior: options?.behavior,
    });
  };

  /**
   * 当滚动容器元素被挂载后,自动滚动到底部
   */
  whenever(scrollTarget, () => {
    const timer = setInterval(scrollToBottom, 60);
    // 持续滚动 1 秒
    setTimeout(() => clearInterval(timer), 1000);
  });

  /**
   * 当滚动条距离底部的距离小于该值时,会自动滚动到底部
   */
  const BOTTOM_THRESHOLD = 100;

  const listElement = computed(() => toValue(options.listElement));
  useResizeObserver(listElement, () => {
    if (!scrollTarget.value) return;
    const { scrollHeight, scrollTop, clientHeight } = scrollTarget.value;
    const scrollBottom = scrollHeight - scrollTop - clientHeight;
    // 如果正在浏览上方内容,则跳过
    if (scrollBottom > BOTTOM_THRESHOLD) return;
    // 如果正在向上方滚动,则跳过
    if (directions.top) return;
    // 正常情况,自动滚动到底部
    scrollToBottom({ behavior: "smooth" });
  });

  return { scrollToBottom };
};
相关推荐
wuhen_n2 小时前
响应式探秘:ref vs reactive,我该选谁?
前端·javascript·vue.js
wuhen_n2 小时前
setup 的艺术:如何组织我们的组合式函数?
前端·javascript·vue.js
lemon_yyds17 小时前
《vue 2 升级vue3 父组件 子组件 传值: value 和 v-model
vue.js
simple_lau17 小时前
Cursor配置MasterGo MCP:一键读取设计稿生成高还原度前端代码
前端·javascript·vue.js
睡不着先生17 小时前
如何设计一个真正可扩展的表单生成器?
前端·javascript·vue.js
wuhen_n20 小时前
Pinia状态管理原理:从响应式核心到源码实现
前端·javascript·vue.js
wuhen_n21 小时前
KeepAlive:组件缓存实现深度解析
前端·javascript·vue.js
wuhen_n21 小时前
Vue Router与响应式系统的集成
前端·javascript·vue.js
Ruihong21 小时前
《VuReact:下一代 Vue 3 -> React 智能编译工具,支持 SFC 与增量迁移》
vue.js