HTML video tag - изменить источник в окне просмотра без атрибута медиа - PullRequest
0 голосов
/ 18 января 2019

Я пытаюсь реализовать видео в 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 не (или не более) не указано в теге источника, если оно находится внутри видео, то 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). Скрытие не препятствует загрузке браузера. SAD!

Третье решение заключалось в использовании второго решения и удалении невидимого компонента из 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 кажется правильным. Понятия не имею, что там делает хром ...

Сначала я действительно не понимаю, почему они удалили атрибут media из тега source внутри тега video. Это не всегда реализовано.

В любом случае: как я могу изменить источник на определенной ширине области просмотра и предотвратить загрузку обоих видео?

1 Ответ

0 голосов
/ 18 января 2019

Простое решение JavaScript (не специфичное для ReactJS, но см. этот компонент для чистого решения 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
}
}
...