|
|
|
|
@ -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()方法
|
|
|
|
|
<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,
|
|
|
|
|
};
|
|
|
|
|
}
|