You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.7 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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()方法
<div
class="wordbox"
ref="contentRef"
@scroll="contentScrollFN"
>
</div>
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,
};
}