|
|
@@ -16,6 +16,7 @@ export default {
|
|
|
data() {
|
|
|
return {
|
|
|
scrollTimer: null,
|
|
|
+ _initTimer: null,
|
|
|
currentTop: 0,
|
|
|
resetHeight: 0,
|
|
|
isScrollable: false
|
|
|
@@ -44,6 +45,11 @@ export default {
|
|
|
mounted() {
|
|
|
console.log('✅ SeamlessScroll: 组件已挂载,准备初始化滚动');
|
|
|
this.initScroll();
|
|
|
+ // 全屏切换后容器高度变化,需要重新初始化滚动
|
|
|
+ this._onFullscreenChange = () => {
|
|
|
+ setTimeout(() => this.initScroll(), 300);
|
|
|
+ };
|
|
|
+ document.addEventListener('fullscreenchange', this._onFullscreenChange);
|
|
|
},
|
|
|
watch: {
|
|
|
data: {
|
|
|
@@ -56,10 +62,22 @@ export default {
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
this.pause();
|
|
|
+ if (this._initTimer) {
|
|
|
+ clearTimeout(this._initTimer);
|
|
|
+ this._initTimer = null;
|
|
|
+ }
|
|
|
+ if (this._onFullscreenChange) {
|
|
|
+ document.removeEventListener('fullscreenchange', this._onFullscreenChange);
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
initScroll() {
|
|
|
this.pause();
|
|
|
+ // 清除上一次未执行完的延时器,防止多个 setTimeout 同时触发 resume
|
|
|
+ if (this._initTimer) {
|
|
|
+ clearTimeout(this._initTimer);
|
|
|
+ this._initTimer = null;
|
|
|
+ }
|
|
|
this.currentTop = 0;
|
|
|
if (this.$refs.scrollRef) this.$refs.scrollRef.scrollTop = 0;
|
|
|
|
|
|
@@ -71,14 +89,12 @@ export default {
|
|
|
|
|
|
this.$nextTick(() => {
|
|
|
// 加大一点延时,给表格充足的撑开时间
|
|
|
- setTimeout(() => {
|
|
|
+ this._initTimer = setTimeout(() => {
|
|
|
+ this._initTimer = null;
|
|
|
const wrapper = this.$refs.scrollRef;
|
|
|
if (!wrapper) return;
|
|
|
-
|
|
|
- const measureEl = wrapper.querySelector(this.measureSelector);
|
|
|
|
|
|
- // 【排查神器】:打印高度对比
|
|
|
- // console.log(`📏 尺寸核对 -> 容器可视高度: ${wrapper.clientHeight}px, 内容真实总高: ${wrapper.scrollHeight}px`);
|
|
|
+ const measureEl = wrapper.querySelector(this.measureSelector);
|
|
|
|
|
|
// 如果容器高度等于或大于内容高度,说明没有溢出,肯定滚不动
|
|
|
if (wrapper.scrollHeight <= wrapper.clientHeight) {
|
|
|
@@ -87,22 +103,29 @@ export default {
|
|
|
}
|
|
|
|
|
|
this.resetHeight = measureEl ? measureEl.offsetHeight / 2 : wrapper.scrollHeight / 2;
|
|
|
- // console.log('🚀 SeamlessScroll: 滚动初始化成功!复位锚点高度为:', this.resetHeight);
|
|
|
|
|
|
this.resume();
|
|
|
- }, 100);
|
|
|
+ }, 100);
|
|
|
});
|
|
|
},
|
|
|
resume() {
|
|
|
if ((!this.data || this.data.length <= this.limit) || this.resetHeight <= 0) return;
|
|
|
+ // 防止重复调用产生多个动画循环
|
|
|
+ this.pause();
|
|
|
const step = () => {
|
|
|
const wrapper = this.$refs.scrollRef;
|
|
|
- if (!wrapper) return;
|
|
|
+ if (!wrapper) {
|
|
|
+ // ref 暂时丢失(Vue 重渲染),不断链,等下一帧重试
|
|
|
+ this.scrollTimer = requestAnimationFrame(step);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
this.currentTop += this.speed;
|
|
|
wrapper.scrollTop = Math.floor(this.currentTop);
|
|
|
|
|
|
- if (wrapper.scrollTop >= this.resetHeight) {
|
|
|
+ // 到达复位点,或者已滚到底部无法继续时,都重置
|
|
|
+ const maxScroll = wrapper.scrollHeight - wrapper.clientHeight;
|
|
|
+ if (wrapper.scrollTop >= this.resetHeight || (maxScroll > 0 && wrapper.scrollTop >= maxScroll)) {
|
|
|
this.currentTop = 0;
|
|
|
wrapper.scrollTop = 0;
|
|
|
}
|