为什么在插入DOM之前播放视频?

时间:2014-11-11 23:03:34

标签: javascript dom html5-video

为什么执行类似以下内容的

var videoBg;
videoBg = $('<video autoplay>');
videoBg.attr({
    'src': 'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4',
    'height': 360,
    'width': 640
});

导致视频在插入页面的DOM之前播放?

用户不应该注意到元素,除非它们位于DOM中的某个位置,这不是一个想法吗?

可见物体与可听物体之间的区别是什么?

2 个答案:

答案 0 :(得分:1)

对我有意义。它被创建你只是没有呈现它。解决方法是

var videoBg;
videoBg = $('<video>');
videoBg.attr({
    'src': 'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4',
    'height': 360,
    'width': 640
});

$('body').append(videoBg);

videoBg.attr('autoplay', true)

编辑进一步深入了解事情,这里是Chrome时间轴的屏幕截图:

enter image description here

这是调用堆栈:

  • jQuery.extend.buildFragment @ jquery-2.1.1.js 第5089行
  • jQuery.parseHTML @ jquery-2.1.1.js 第8810行
  • jQuery.fn.init @ jquery-2.1.1.js 第2735行
  • jQuery @ jquery-2.1.1.js 第76行
  • (anonymous function) @ test.html 第28行
  • jQuery.Callbacks.fire @ jquery-2.1.1.js 第3073行
  • jQuery.Callbacks.self.fireWith @ jquery-2.1.1.js 第3185行
  • jQuery.extend.ready @ jquery-2.1.1.js 第3391行
  • completed @ jquery-2.1.1.js 第3407行

值得注意的是:

(anonymous function) @ test.html 第28行是:

videoBg = $('<video autoplay>');

更重要的是,jQuery.extend.buildFragment @ jquery-2.1.1.js 第5089行,是此块的一部分:

// Convert html into DOM nodes
} else {
  tmp = tmp || fragment.appendChild( context.createElement("div") );

  // Deserialize a standard representation
  tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
  wrap = wrapMap[ tag ] || wrapMap._default;
  tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];

  // Descend through wrappers to the right content
  j = wrap[ 0 ];
  while ( j-- ) {
    tmp = tmp.lastChild;
  }

  // Support: QtWebKit
  // jQuery.merge because push.apply(_, arraylike) throws
  jQuery.merge( nodes, tmp.childNodes );

  // Remember the top-level container
  tmp = fragment.firstChild;

  // Fixes #12346
  // Support: Webkit, IE
  tmp.textContent = "";
}

注意第tmp = tmp || fragment.appendChild( context.createElement("div") );

在其他地方,它指出var fragment = document.createDocumentFragment()

将我们引导至documentation on createDocumentFragment(),其中声明:

  

DocumentFragments是DOM节点。它们永远不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段由其所有子代替。

     

由于文档片段在内存中而不是主DOM树的一部分,因此将子项附加到它不会导致页面重排(计算元素的位置和几何)。因此,使用文档片段通常会带来更好的性能。

答案 1 :(得分:1)

audiocanvas和其他人一样,在JavaScript中创建的<video>元素仍然被动地发挥作用,即使它们不在渲染的DOM中。

否则

videoBg = $("<video>");

创建元素。它存在,它是功能性的。但是,它还不是你网页DOM中的某个东西。

它只是在DOM树中没有可以使其可渲染的连接。

如果您不希望autoplay开始自动播放,请不要使用video。而是以编程方式开始播放:

var videoBg;
videoBg = $("<video>");
videoBg.attr({
    src: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",
    height: 360,
    width: 640
});
// When you're ready...
videoBg[0].load(); // Start loading `src`
videoBg[0].play(); // And play

精化(编辑

我注意到你添加了你的问题:

  

可见物体与可听物体之间的区别是什么?

从概念上讲,并没有什么不同。 <{1}}元素被浏览器视为需要以可视方式呈现的内容。

你的body元素仍在那里并且正在播放,除了它没有连接任何会导致实际帧在你的显示器上呈现的事实。

事实上,如果您在JavaScript中创建video并且实际上从未将其放在video下的某个DOM树中,您仍然可以“获取”可视数据,例如,绘制body框架到可见DOM中的video

canvas

对于ctx.drawImage(videoElm, 0, 0); 元素,如果不将其添加到可见DOM,它将不会呈现控件,搜索栏等。

然而,在大多数情况下,它仍会播放扬声器(因为浏览器会将声音连接到扬声器,而不管显示器上可见DOM中的audio元素是什么)。

在很多方面,如果audio元素没有附加到您的可见DOM,则大致相当于仅将<video>应用于body