import { ref, onMounted, onUnmounted } from 'vue'; /** @example 1. 页面引入该hooks, 并调用useAutoScroll(),返回三个值:canAutoScroll, contentRef, contentScrollFN import { useAutoScroll } from '@/hooks/useAutoScroll'; const { canAutoScroll, contentRef, contentScrollFN } = useAutoScroll(); 2. 需要配置自动滚动的dom加上contentRef属性(contentRef名称不能修改,必须匹配),并监听scroll调用contentScrollFN()方法
3. 在请求流式数据时,设置canAutoScroll为true ### 注意事项 滚动的dom样式要求 .wordbox { overflow-y: auto; overflow-x: hidden; scrollbar-width: none; word-break: break-all; } .wordbox::-webkit-scrollbar { display: none; } */ export function useAutoScroll() { let prescrollHeight = 0; let touchStartPointY = 0; const canAutoScroll = ref(false); const contentRef = ref(null); const contentScrollFN = () => { if (canAutoScroll.value === true) { return; } // +10 这里是一个缓冲区,只要快到底部就触发自动滚动 if (contentRef.value.scrollTop + contentRef.value.clientHeight + 10 >= contentRef.value.scrollHeight) { console.log('设置开始自动滚动'); canAutoScroll.value = true; } }; const observeScrollFN = () => { const observe = new MutationObserver((mutations) => { if (!contentRef.value || !canAutoScroll.value) { return; } mutations.forEach((mutation) => { if (mutation.type !== 'childList') { return; } if (prescrollHeight != contentRef.value.scrollHeight) { contentRef.value.scrollTo({ top: contentRef.value.scrollHeight, behavior: 'smooth', }); prescrollHeight = contentRef.value.scrollHeight; } }); }); const config = { childList: true, subtree: true, }; observe.observe(contentRef.value, config); }; const touchstartFN = (event) => { touchStartPointY = event.targetTouches[0].pageY; }; const touchmoveFN = (event) => { if (event.targetTouches.length > 1) { return; } // event.targetTouches[0].pageY - touchStartPointY > 0 即为内容往上滑动 // 5这里也是缓冲区 if (canAutoScroll.value === true && event.targetTouches[0].pageY - touchStartPointY > 5) { canAutoScroll.value = false; } }; const touchendFN = () => { touchStartPointY = 0; }; const wheelFN = (event) => { /** 修复mac下whell触发后惯性继续触发问题 */ if (event.deltaY < 0) { // console.log('向上滚动'); canAutoScroll.value = false; } else if (event.deltaY > 0) { // console.log('向下滚动'); } }; onMounted(() => { observeScrollFN(); window.addEventListener('touchstart', touchstartFN); window.addEventListener('touchmove', touchmoveFN); window.addEventListener('touchend', touchendFN); window.addEventListener('wheel', wheelFN); }); onUnmounted(() => { window.removeEventListener('touchstart', touchstartFN); window.removeEventListener('touchmove', touchmoveFN); window.removeEventListener('touchend', touchendFN); window.removeEventListener('wheel', wheelFN); }); return { canAutoScroll, contentRef, contentScrollFN, }; }