We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
使用ali-player,需要加载其js库以及css库,同时ali-player仍不支持npm包的引入方式。所以最简单的方式是在document.ejs(或其他入口html)中标签引入:
<link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.3/skins/default/aliplayer-min.css" /> <script type="text/javascript" charset="utf-8" src="https://g.alicdn.com/de/prismplayer/2.9.3/aliplayer-min.js" ></script>
但是这样就会引入一个新的问题,由于项目是单页面应用,所有的页面都会主动去请求这两个文件,但是我只是在其中的一个详情页面需要用到ali-player,就造成了一定的资源浪费。所以我期望只在页面进入到详情页面的时候,再去加载ali-player。
思路是,在页面didMount的时候,去动态往页面上插入标签,异步加载完成后,然后初始化播放器:
// async AliplayerSDK inject to html const loadSDK = () => { const loaded = !!window.Aliplayer; return ( loaded ? Promise.resolve() : Promise.all([ addStyleLink(playerCDN.stylelink), addScript(playerCDN.script), ]) ).catch((err) => { window.console.log(err); }); }; const playerCDN = { stylelink: 'https://g.alicdn.com/de/prismplayer/2.9.3/skins/default/aliplayer-min.css', script: 'https://g.alicdn.com/de/prismplayer/2.9.3/aliplayer-min.js', }; function addScript(source: string): Promise<void> { return new Promise((resolve, reject) => { const s = document.createElement('script'); s.src = source; s.setAttribute('charset', 'utf-8'); document.body.appendChild(s); s.onload = () => { resolve(); }; s.onerror = () => { reject(); }; }); } function addStyleLink(source: string): Promise<void> { return new Promise((resolve, reject) => { const l = document.createElement('link'); l.type = 'text/css'; l.rel = 'stylesheet'; l.href = source; document.head.appendChild(l); l.onload = () => { resolve(); }; l.onerror = () => { reject(); }; }); }
在我们使用到ali-player的页面中,didMount时,动态插入标签:
const [sdkLoaing, { setFalse }] = useBoolean(true); useEffect(() => { Promise.all([ loadSDK(), ]).then(setFalse); }, []); return sdkLoading ? null : <Ali-player />
由于项目是一组H5网页,使用了andriod端的webview容器。唤起全屏(requestFullScreen)需要webview容器支持,要在原生端增加适配代码。同时,点击退出全屏按钮(exitFullScreen )的时候,要通过JS桥接发消息给原生端,由app来控制webivew退出全屏。
android原生端处理,前端只需要监听退出全屏事件,发送消息给原生端,例如 ali-player 中:
let isFullScreen = false; _player.on('requestFullScreen', (e) => { if (!isFullScreen) { isFullScreen = true; } }); _player.on('cancelFullScreen', (e) => { if (isFullScreen) { isFullScreen = false; Utils.cancelFullScreen(); // 通过js桥接的通知app端来退出webview的全屏 } });
轮播组件,例如(antd-mobile-Carousel或者swiper.js),都是使用css动画中的transform属性来实现的,在和播放器底部控制条使用的 position(relative/absolute)混合的话,会导致z-index在某些浏览器下表现奇怪,在safari内核的浏览器中,就会出现被盖住的情况。
给播放器控制条增加样式,使用 transform:translateZ(100px),将控制条也 transform 上来。ali-player中的处理方式:
.prism-controlbar { // 解决:ios 视频覆盖控制条问题 transform: translateZ(100px); }
与轮播组件产生了手势冲突。
由于轮播组件使用的是swiper/react,可以通过noSwiping属性设置不可拖动块,拖动视频控制条的时,禁止轮播手势。同时,在触摸控制条的边缘的时候,也会触发轮播手势,可以通过给控制条新增一个伪元素,来增加操作热区。
noSwiping
// prism-controlbar 是 ali-player 控制条的类名 <Swiper spaceBetween={20} slidesPerView={1} onSwiper={setSwiperController} onSlideChange={onSlideChange} pagination={{ clickable: false }} // noSwiping when operating the controlbar noSwiping noSwipingClass="prism-controlbar" > {list.map((item, index) => { return ( <SwiperSlide key={index}> <Player id={`player-${item.id || index}`} ref={(ref) => { if (ref) playerRefs.current[index] = ref; }} config={config} /> </div> </SwiperSlide> ); })} </Swiper>
通过伪元素来增大操作热区,覆盖ali-player的样式:
.prism-controlbar { // 扩大热区 position: relative; &::after { position: absolute; width: 100%; height: 10px; left: 0; top: -10px; content: ''; background: transparent; z-index: 9; pointer-events: none; } }
是和safari浏览器采用的策略有关。safari在请求视频或者这类文件的时,期望用分段的方式来获取视频文件,而不是整个视频文件都请求下来,这种策略是为了节约流量以及提高响应速度。分段请求文件则是通过http的请求头range,以及响应头content-range来实现的。如果服务端不支持处理这两个头,就会导致视频无法播放。 chrome浏览器,兼容性比较好,无论你有没有实现分段请求,都能正确处理。
safari分段请求视频文件的具体流程是这样的:
以下是nodejs作为http服务端的处理方式:
// ./app.js // run: node app.js // 根目录下,需要 test.mp4 视频文件用于测试。 const { createServer } = require('http'); const fs = require('fs'); // bytes=n-m => [n,m] function getRange(range, stats) { const r = range.match(/=(\d+)-(\d+)?/); const start = r[1]; const end = r[2] || stats.size - 1; return [parseInt(start), parseInt(end)]; } createServer((req, res) => { const { headers } = req; let { range } = headers; // 获取请求头 range, bytes=n-m,获取n到m个字节的数据 if (typeof range === 'undefined') { range = 'bytes=0-1'; // 未发送请求头,设置一个默认值 } if (req.url.includes('/test.mp4')) { fs.stat('./test.mp4', (err, stats) => { const [start, end] = getRange(range, stats); // 获取当前片段的范围 res.setHeader('Content-Range', `bytes ${start}-${end}/${stats.size}`); // 响应头 - Content-Range: bytes 0-1/6990051 res.setHeader('Content-Type', 'video/mp4'); // 响应头 - 文件类型 res.setHeader('Content-Length', end == start ? 0 : end - start + 1); // 响应头 - 返回的字节长度 res.writeHead(206); // 206 - Partial Content 部分内容 fs.createReadStream('./test.mp4', { start, end }).pipe(res); // 写入body }); } else { res.end(); } }).listen(3000, () => { console.log(`server listen on localhost:3000`); // safari 浏览器访问 localhost:3000/test.mp4 就能看到视频了 });
和浏览器有关,即便是z-index,也无法改变video的层级。
<video loop playsinline="true" webkit-playsinline="true" x-webkit-airplay="allow" airplay="allow" autoplay x5-video-player-type="h5" x5-video-player-fullscreen="false" x5-video-orientation="portrait" ></video>
ali-player的示例代码:
const meta = { videoWidth: 0,// 原视频的宽度 videoHeight: 0,// 原视频的高度 }; block: () => { if (!isAndroid) { return; } // 获取video的dom标签 const i = player.current; const video = i.tag; meta.videoWidth = video.offsetWidth; meta.videoHeight = video.offsetHeight; // 暂停视频,设置视频的宽度高度为0 i.pause(); i.setPlayerSize(0, 0); // 新建一个占位符dom,替换原来的位置 const ele = document.createElement('div'); ele.style.width = `${meta.videoWidth}px`; ele.style.height = `${meta.videoHeight}px`; ele.setAttribute('id', `block-${id}`); ele.setAttribute('class', 'visible'); meta.childId = `block-${id}`; // 如果视频有占位图,设置背景图片 if (config.cover) { ele.style.backgroundImage = `url( ${config.cover})`; ele.style.backgroundRepeat = 'no-repeat'; ele.style.backgroundPosition = 'center'; ele.style.backgroundSize = 'cover'; } // 增加样式,将占位div加到页面上 addClassName(containerRef.current, 'hidden-container'); containerRef.current.appendChild(ele); }, unblock: () => { if (!isAndroid) { return; } // 将原视频复原 const i = player.current; i.setPlayerSize(`${meta.videoWidth}px`, `${meta.videoHeight}px`); removeClassName(containerRef.current, 'hidden-container'); const child = document.getElementById(meta.childId); if (child) { containerRef.current.removeChild(child); } }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
问题:React单页面应用加载ali-playerSDK的一种方式
原因
使用ali-player,需要加载其js库以及css库,同时ali-player仍不支持npm包的引入方式。所以最简单的方式是在document.ejs(或其他入口html)中标签引入:
但是这样就会引入一个新的问题,由于项目是单页面应用,所有的页面都会主动去请求这两个文件,但是我只是在其中的一个详情页面需要用到ali-player,就造成了一定的资源浪费。所以我期望只在页面进入到详情页面的时候,再去加载ali-player。
解决
思路是,在页面didMount的时候,去动态往页面上插入标签,异步加载完成后,然后初始化播放器:
在我们使用到ali-player的页面中,didMount时,动态插入标签:
问题:android手机的webview中,视频无法唤起全屏、退出全屏。
原因
由于项目是一组H5网页,使用了andriod端的webview容器。唤起全屏(requestFullScreen)需要webview容器支持,要在原生端增加适配代码。同时,点击退出全屏按钮(exitFullScreen )的时候,要通过JS桥接发消息给原生端,由app来控制webivew退出全屏。
解决
android原生端处理,前端只需要监听退出全屏事件,发送消息给原生端,例如 ali-player 中:
问题:ios下,使用轮播组件下的ali-player,视频底部控制条被视频盖住。
原因
轮播组件,例如(antd-mobile-Carousel或者swiper.js),都是使用css动画中的transform属性来实现的,在和播放器底部控制条使用的 position(relative/absolute)混合的话,会导致z-index在某些浏览器下表现奇怪,在safari内核的浏览器中,就会出现被盖住的情况。
解决
给播放器控制条增加样式,使用 transform:translateZ(100px),将控制条也 transform 上来。ali-player中的处理方式:
问题:使用轮播组件下的ali-player,拖动视频底部控制条的视频进度条会触发轮播手势。
原因
与轮播组件产生了手势冲突。
解决
由于轮播组件使用的是swiper/react,可以通过
noSwiping
属性设置不可拖动块,拖动视频控制条的时,禁止轮播手势。同时,在触摸控制条的边缘的时候,也会触发轮播手势,可以通过给控制条新增一个伪元素,来增加操作热区。通过伪元素来增大操作热区,覆盖ali-player的样式:
问题:部分视频在safari内核浏览器下加载失败,无法播放。
原因
是和safari浏览器采用的策略有关。safari在请求视频或者这类文件的时,期望用分段的方式来获取视频文件,而不是整个视频文件都请求下来,这种策略是为了节约流量以及提高响应速度。分段请求文件则是通过http的请求头range,以及响应头content-range来实现的。如果服务端不支持处理这两个头,就会导致视频无法播放。
chrome浏览器,兼容性比较好,无论你有没有实现分段请求,都能正确处理。
safari分段请求视频文件的具体流程是这样的:
解决
以下是nodejs作为http服务端的处理方式:
问题:部分android机型下,video标签无法被其他标签覆盖,始终在最顶层。
原因
和浏览器有关,即便是z-index,也无法改变video的层级。
解决
ali-player的示例代码:
The text was updated successfully, but these errors were encountered: