diff --git a/src/hooks/useAutoScroll.ts b/src/hooks/useAutoScroll.ts new file mode 100644 index 0000000..4bed007 --- /dev/null +++ b/src/hooks/useAutoScroll.ts @@ -0,0 +1,124 @@ +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, + }; +} diff --git a/src/views/demo/sseFetch.vue b/src/views/demo/sseFetch.vue index a6e3e65..537a3b9 100644 --- a/src/views/demo/sseFetch.vue +++ b/src/views/demo/sseFetch.vue @@ -15,40 +15,37 @@
- + >