不知道有没有人遇到过这个bug: video组件进入全屏再退出后会自动返回顶部(目前已知ios)。
我在论坛里面也看到有人提过这个bug,官方态度是未解决。
我整理了一下这个踩坑心得:
- 一开始我并没有觉得这2个组件弄在一起会有什么bug(在ScrollView里面用Video组件)。
讲道理这个非常常用,想要长列表,上拉加载和下拉刷新必须用这个组件,想要列表有视频必须用video组件。
我写完后也没发现什么问题,除了有点卡顿问题,然后点开视频播放没问题,实机测试安卓设备也没有问题,但是在苹果设备全屏播放后退出全屏会顶到顶部((灬ꈍ ꈍ灬))什么奇怪的bug。
我翻阅百度和论坛,没看的有什么好解决方法。
video组件进入全屏再退出后会自动返回顶部(目前已知ios)
小程序视频退出全屏产生问题
我尝试了下面评论里面的一个方案:
提供一个曲线救国方案:
1 监听页面的onPageScroll事件,实时全局保存scrollTop
2 监听video的bindfullscreenchange事件(视频进入和退出全屏时触发),当进入全屏,再记录一个值videoScrollTop,将1中的scrollTop设置给它
3 退出全屏时,wx.pageScrollTo({scrollTop: videoScrollTop})
我尝试了一下,并不完美,会一瞬间顶到顶部。
const resRef = ref.current as any;
const changeScrollTop = blo => {
if (blo) {
wx.setStorageSync("videoScrollTop", resRef.getScrollTop());
} else {
resRef.scrollToTop(wx.getStorageSync("videoScrollTop"));
}
};
//封装上拉加载下拉刷新里面
/**
* 滚动到顶部
*/
scrollToTop(top = 0) {
//跳转到目标top
this.setState({ scrollTop: top + Math.random() * 0.001 });
}
//视频
<Video
onFullscreenChange={event => {
wx.setStorageSync("conditionalRefresh", false);
changeScrollTop(event.detail.fullScreen);
}}
src={img.url}
/>
我放弃了这个方案。
-
进入拉锯战。我尝试了很多,比如通过动画方式掩盖一瞬间顶到顶部。上面的方法补丁。但是体验很不友好,我放弃了。
在某天我灵光一现,我想到了在Video的父级再加一个ScrollView,然后在浏览容器固定高度。用魔法打败魔法。。哈哈哈哈,尝试了一下,发现是可以的,但是我开心没2分钟,发现很卡很卡,根本没办法浏览。
-
以上我都准备放弃了,在心里骂了一万遍小程序开发团队!!!我翻阅小程序官方文档,我突然发现了官方自带下拉刷新和上拉加载。
-
开干,我弃掉ScrollView,采用官方下拉刷新和上拉加载。
我用Taro Hooks,你们可以用原生写。
import Taro, {
usePullDownRefresh,
useReachBottom,
usePageScroll,
useScope
} from "@tarojs/taro";
//私有获取封装的列表useGetList,可以采用自己的方式
// 获取数据列表
const { noData, state, noMore, list, fetchList, setList } = useGetList(
[] as any,
`xxx`,
{ isDebance: true }
);
const onRefresh = useCallback(() => fetchList(1), [fetchList]);
usePullDownRefresh(() => {
onRefresh();
Taro.stopPullDownRefresh();
Taro.hideNavigationBarLoading();
});
useReachBottom(() => {
if (!noMore) {
fetchList();
}
});
// 视频播放
const [videoIndex, setVideoIndex] = useState(-1 as any);
// 播放视频
const videoPlay = idx => {
if (videoIndex <= 0) {
// 没有播放时播放视频
setVideoIndex(idx);
const videoContext = Taro.createVideoContext("video" + idx);
videoContext.play();
} else {
// 停止正在播放的视频
const videoContextPrev = Taro.createVideoContext("video" + videoIndex);
videoContextPrev.stop();
// 将点击视频进行播放
setVideoIndex(idx);
const videoContextCurrent = Taro.createVideoContext("video" + idx);
videoContextCurrent.play();
}
};
const stopPlay = idx => {
const videoContextPre = Taro.createVideoContext("index" + idx);
videoContextPre.pause();
};
const scope = useScope();
const windowHeight = Taro.getSystemInfoSync().windowHeight; // 可视区域高度
usePageScroll(() => {
// eslint-disable-next-line no-undef
if (videoIndex >= 0 && !isFullscreen) {
const id = videoIndex;
selectRect("#item" + id, scope).then(rect => {
// 我查询的是包裹视频的元素,可根据需求
const top = rect.top; // 距离顶部高度
const bottom = rect.bottom;
const vh = rect.height; // 元素高度
if (top < 0 || bottom > vh + windowHeight) {
// 当视频距离顶部为零,测了下,这个为0,视频不可见。
setVideoIndex(-1);
}
});
}
});
const [isFullscreen, setIsFullscreen] = useState(false);
const onFullscreenChange = blo => {
setIsFullscreen(blo);
};
//视频组件
<View className={styles.itemVideoBox}>
{idx === videoIndex && (
<Video
className={styles.video}
src={img.url}
autoplay
onPause={event => {
event.stopPropagation();
stopPlay(idx);
}}
onFullscreenChange={event => {
event.stopPropagation();
onFullscreenChange(event.detail.fullScreen);
}}
id={`video${idx}`}
/>
)}
{idx !== videoIndex && (
<View
key={`${"id" + index}`}
className={styles.posterImgBlock}
onClick={event => {
event.stopPropagation();
videoPlay(idx);
}}
>
<Image
src={
img.thumb
? img.thumb
: "默认封面图地址"
}
mode="aspectFill"
lazyLoad
/>
<Image
className={styles.palyBtn}
src='播放按钮'
mode="aspectFill"
lazyLoad
/>
</View>
)}
</View>
less 不要设置高度
page {
overflow: auto !important;
}
.posterImgNone {
display: none;
}
.posterImgBlock {
display: block;
}
.itemVideoBox {
position: relative;
}
.posterImgBlock,
.posterImgNone {
margin-bottom: 3px;
width: 100%;
height: 200px;
margin-right: 3px;
position: absolute;
top: 0;
left: 0;
image,
img {
width: 100%;
height: 100%;
border-radius: 5px;
}
.palyBtn {
width: 60px;
height: 60px;
border-radius: 0;
position: absolute;
top: 50%;
left: 50%;
margin-top: -30px;
margin-left: -30px;
}
}
/**
* 查询元素大小
*
* @export
* @param {string} name
* @param {*} scope
* @returns
*/
export function selectRect(name: string, scope: any) {
return new Promise<wx.NodesRef.BoundingClientRectCallbackResult>((resolve) => {
setTimeout(() => {
const query = wx.createSelectorQuery().in(scope);
query.select(name).boundingClientRect((res) => {
resolve(res as wx.NodesRef.BoundingClientRectCallbackResult);
}).exec();
}, 0)
});
}
我随便加上了列表视频 及 滑过该视频 停止播放。
大功告成!
贴下github代码:https://github.com/ihopefulChina/fix-scrollview-video-bug
至此是遇到了这个大坑过程,以及解决心得。希望能给你们一些帮助。