HTML 视频标签 - 在没有媒体属性的情况下更改视口上的来源
HTML video tag - change source on viewport without media attribute
我正在尝试使用 React 在 HTML 中实现一个视频。因此,如果视口宽度小于 750px,我想将视频源更改为更小的分辨率/更小的文件(因为高数据传输等)。
所以在一个完美的 HTML 世界中,你会构建这个:
<video controls>
<source src="video-small.mp4" type="video/mp4" media="all and (max-width: 750px)">
<source src="video.mp4" type="video/mp4">
</video>
由于 media
不是(或不再是)specified in the source tag if it's inside of a video tag,我不能再使用它了。因为Chrome显示的是第一个来源,即手机视频。无论是台式机还是移动设备。
第二种解决方案 是包裹一个容器并将 display: none;
设置为不可见视频:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({theme}) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({theme}) => theme.media.mobile`
display: none;
`}
`
const VideoComponent = ({
srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
}) => (
<React.Fragment>
<MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>
<DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>
</React.Fragment>
)
在这种情况下,显示的是正确的视频,但两个视频都已下载(在 Chrome 中)。隐藏不会阻止浏览器下载。悲伤!
第三个解决方案是使用第二个解决方案并从 DOM:
中删除不可见的组件
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
import {sizes} from '../../lib/ThemeProvider/media'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({ theme }) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({ theme }) => theme.media.mobile`
display: none;
`}
`
class VideoComponent extends React.Component {
state = {
showMobileSrc: true
}
componentDidMount() {
this.resize()
window.addEventListener('resize', this.resize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.resize)
}
resize = () => {
if (window.innerWidth >= sizes.mobile) {
this.setState({ showMobileSrc: false })
} else {
this.setState({ showMobileSrc: true })
}
}
render() {
const { srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
} = this.props
const {showMobileSrc} = this.state
return (
<React.Fragment>
{showMobileSrc && <MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>}
{!showMobileSrc && <DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>}
</React.Fragment>
)
}
}
但是 chrome 正在下载这两个视频。 HTML 似乎是正确的。不知道 chrome 在那里做什么..
首先,我真的不明白为什么他们从视频标签内的源标签中删除了媒体属性。这并没有始终如一地实施。
无论如何:我怎样才能在定义的视口宽度更改源并防止下载两个视频?
简单 JavaScript 解决方案(不是特定于 ReactJS,但请参阅 this component 了解纯 ReactJS 解决方案)
if (matchMedia) {
var mq = window.matchMedia("(min-width: 600px)");
mq.addListener(WidthChange);
}
function WidthChange(mq) {
if (mq.matches) {
// set source to desktop
} else {
// set source to mobile
}
}
我正在尝试使用 React 在 HTML 中实现一个视频。因此,如果视口宽度小于 750px,我想将视频源更改为更小的分辨率/更小的文件(因为高数据传输等)。
所以在一个完美的 HTML 世界中,你会构建这个:
<video controls>
<source src="video-small.mp4" type="video/mp4" media="all and (max-width: 750px)">
<source src="video.mp4" type="video/mp4">
</video>
由于 media
不是(或不再是)specified in the source tag if it's inside of a video tag,我不能再使用它了。因为Chrome显示的是第一个来源,即手机视频。无论是台式机还是移动设备。
第二种解决方案 是包裹一个容器并将 display: none;
设置为不可见视频:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({theme}) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({theme}) => theme.media.mobile`
display: none;
`}
`
const VideoComponent = ({
srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
}) => (
<React.Fragment>
<MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>
<DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>
</React.Fragment>
)
在这种情况下,显示的是正确的视频,但两个视频都已下载(在 Chrome 中)。隐藏不会阻止浏览器下载。悲伤!
第三个解决方案是使用第二个解决方案并从 DOM:
中删除不可见的组件import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
import {sizes} from '../../lib/ThemeProvider/media'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({ theme }) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({ theme }) => theme.media.mobile`
display: none;
`}
`
class VideoComponent extends React.Component {
state = {
showMobileSrc: true
}
componentDidMount() {
this.resize()
window.addEventListener('resize', this.resize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.resize)
}
resize = () => {
if (window.innerWidth >= sizes.mobile) {
this.setState({ showMobileSrc: false })
} else {
this.setState({ showMobileSrc: true })
}
}
render() {
const { srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
} = this.props
const {showMobileSrc} = this.state
return (
<React.Fragment>
{showMobileSrc && <MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>}
{!showMobileSrc && <DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>}
</React.Fragment>
)
}
}
但是 chrome 正在下载这两个视频。 HTML 似乎是正确的。不知道 chrome 在那里做什么..
首先,我真的不明白为什么他们从视频标签内的源标签中删除了媒体属性。这并没有始终如一地实施。
无论如何:我怎样才能在定义的视口宽度更改源并防止下载两个视频?
简单 JavaScript 解决方案(不是特定于 ReactJS,但请参阅 this component 了解纯 ReactJS 解决方案)
if (matchMedia) {
var mq = window.matchMedia("(min-width: 600px)");
mq.addListener(WidthChange);
}
function WidthChange(mq) {
if (mq.matches) {
// set source to desktop
} else {
// set source to mobile
}
}