HTML视频标签-更改视口上的源,而没有媒体属性

时间:2019-01-18 10:15:14

标签: html reactjs video responsive viewport

我正在尝试用react来实现HTML视频。因此,如果视口的宽度小于750像素,我想将视频源更改为较小的分辨率/较小的文件(因为数据传输量较高等)。

因此,在完美的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 ta g,因此我不能再使用它了。由于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似乎是正确的。不知道铬在那做什么。

首先,我真的不明白为什么他们从视频标签内的源标签中删除了媒体属性。这并不是始终如一地实现的。

无论如何:如何在定义的视口宽度下更改源并防止下载两个视频?

1 个答案:

答案 0 :(得分:1)

简单的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
}
}