在 DOM 中仅渲染子元素而不是整个 JSX 元素

Posted

技术标签:

【中文标题】在 DOM 中仅渲染子元素而不是整个 JSX 元素【英文标题】:Render only child element in DOM instead of the whole JSX element 【发布时间】:2021-07-21 02:24:24 【问题描述】:

我从一位用户那里复制了这个文件,该文件展示了如何使用名为 videoJS 的 npm 库显示视频:

import React,  useEffect, useRef  from 'react'
import VideoJs from 'video.js'


const videoJsOptions = 
  controls: true,
  autoplay: true,
  fluid: false,
  loop: true,
  width: '100%',
  aspectRatio: '4:3',
  children: [
      'MediaLoader'
  ],


const VideoPlayer = ( url ) => 
  const videoContainer = useRef()

  //  Setup the player
  useEffect(() => 

    //  Setting content like this because player.dispose() remove also the html content
    videoContainer.current.innerHTML = `
      <div data-vjs-player>
        <video class="video-js" />
      </div>
    `

    //  Setting logger level to all for dev
    if (process.env.NODE_ENV === 'development') 
      VideoJs.log('all')
    

    const player = VideoJs(videoContainer.current.querySelector('video'), videoJsOptions, async () => 
      player.src( src: url, type: 'video/mp4' );
    )

    //  When destruct dispose the player
    return () => player.dispose()
  , [url])

  console.log(videoContainer)
  
  return <div ref=videoContainer />


export default VideoPlayer

问题在于渲染的父 div 将实际视频推到页面下方:

我想删除这个父 div,同时只保留视频元素。我该怎么做?

【问题讨论】:

当您设置videoContainer.current.innerHTML = `&lt;div data-vjs-player&gt;&lt;video class="video-js" /&gt;&lt;/div&gt;` 时,您正在积极渲染父div...为什么不只渲染&lt;video /&gt; 元素? 嗨,@SethLutske 感谢您的建议。不幸的是,这是我尝试的第一件事。似乎会自动生成这个父 div: 为什么不直接使用 css 定位父 div 并删除所有边距和填充? 成功了!谢谢你。我在 .video-js 类的 padding-top 上使用了 !important 【参考方案1】:

您需要加载 video.js CSS 文件。例如:

import 'video.js/dist/video-js.min.css';

在演示中,我从 CDN 加载 CSS 文件,您可以看到它看起来不错。

注意:该演示使用我在 React 中实现的 video.js。内部组件Player 向父级公开了一个命令式 API,并且由于内部的 JSX 不依赖于更改 props,它不会重新渲染实际的 DOM。它只会在播放器卸载时处理掉它。

const  useEffect, useRef, forwardRef, useImperativeHandle  = React;

const videoJsOptions = 
  controls: true,
  autoplay: true,
  loop: true,
  width: '100%',
  aspectRatio: '16:9',
  children: [
      'MediaLoader'
  ],


const Player = forwardRef((_, ref) => 
  const video = useRef();
  const player = useRef();
  
  useEffect(() => 
    player.current = videojs(video.current, videoJsOptions);
    
    return () => 
      player.current.dispose();
    ;
  , []);
  
  useImperativeHandle(ref, () => (
    play: (src, type) => 
      const p = player.current;
      
      p.ready(() => 
        p.src( src, type );
      );
    
  ));
  
  return (
    <div data-vjs-player>
      <video className="video-js" ref=video />
    </div>
  );
);

const VideoPlayer = ( url, type = 'video/mp4' ) => 
  const player = useRef();
  
  useEffect(() => 
    player.current.play(url, type);
  , [url, type]);
  
  return <Player ref=player />;


ReactDOM.render(
  <VideoPlayer url="https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4" />,
  root
);
html, body 
  margin: 0;
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.0.0/video.min.js" integrity="sha512-LiILFcpZ9QKSH41UkK59Zag/7enHzqjr5lO2M0wGqGn8W19A/x2rV3iufAHkEtrln+Bt+Zv1U6NlLIp+lEqeWQ==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.0.0/alt/video-js-cdn.min.css" integrity="sha512-zki7IiwYvLzVZouKA+V/vtIuW7cK8M2ug1kaRBItuBWG8TDvA6jrtjhKPOrz3RFGpt9OQC/xE7DUfsrHxoBXxg==" crossorigin="anonymous" />

<div id="root"></div>

【讨论】:

以上是关于在 DOM 中仅渲染子元素而不是整个 JSX 元素的主要内容,如果未能解决你的问题,请参考以下文章

在渲染函数中调用返回 JSX 元素的函数

根据条件渲染 JSX 元素

在 Helper 函数中渲染 JSX 元素数组

如何通过选择器访问 DOM 元素

使用 CSS 生成的内容(即伪元素)是不是比添加更多 DOM 元素更有效(即解析/渲染更快)?

React事件处理