为什么视频标记不在此视频播放器 Web 组件中加载?



我正在尝试构建一个视频播放器Web组件,但似乎无法正确渲染videosource元素。

customElements.define('video-player',
class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('video-player-template').content;
console.log(template)
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(template.cloneNode(true));
}
}
);
<template id="video-player-template">
<video controls width="720" height="380" muted autoplay>
<slot name="video-src" />
</video>
<slot></slot>
</template>

<video-player>
<h1>Video player web component</h1>
<source slot="video-src" src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm" type="video/webm" />
</video-player>

为什么video元素不呈现?

请参阅文档:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video

<video>希望<source>元素作为立即子元素,
因此不能在那里使用<slot>
(<table>也是如此,不能有<slot>(

<video-player src="...">Web组件中提取src
然后创建该<source>标记。

我已经为一个完整的示例添加了所有shadowDOM样式选项

customElements.define('video-player',
class extends HTMLElement {
constructor() {
super()
.attachShadow({mode:'open'})
.append(document.getElementById(this.nodeName).content.cloneNode(true));
}
connectedCallback() {
let src = this.getAttribute("source");
let ext = src.split(".").slice(-1)[0];
this.shadowRoot
.querySelector("video")
.innerHTML = `<source src="${src}" type="video/${ext}">`;
}
}
);
<video-player source="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm">
<span slot="title">A beautiful video</span>
<div class="desc">My video description</div>
</video-player>
<video-player source="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm">
<span slot="title">Another beautiful video</span>
<div class="desc">And more description</div>
</video-player>
<template id="VIDEO-PLAYER">
<style>
:host { display:inline-block }
h1 { margin:0px;background:var(--bgcolor,green);text-align:center }
</style>
<div part="videoContainer">
<h1><slot name="title"></slot></h1>
<video controls width="100%" muted></video>
<div><slot><!-- all non-slot labeled content goes here --></slot></div>
</div>
</template>
<style>
video-player {
font: 10px Arial; /* Inheritable styles style shadowDOM */
width: 240px;
--bgcolor: gold; /* CSS properties can style shadowDOM */
}
.desc { /* container/global CSS styles slotted content!!!!  */
width: 100%;
background: beige;
}
::part(videoContainer){ /* shadowParts style all usages in shadowDOM */
border: 5px solid grey;
}
</style>

ShadowDOM的样式为:

  • 阴影DOM 内的<style>

  • 可继承样式
    https://lamplightdev.com/blog/2019/03/26/why-is-my-web-component-inheriting-styles/

  • (级联(CSS属性

  • shadowParts(和主题(
    https://meowni.ca/posts/part-theme-explainer/

  • <slot>反射的,它们不是由shadowDOM设计的,而是由其容器设计的
    请参阅::分时段内容

  • (2022年2月(Constructable StyleSheets仍然是Chromium的专属派对
    https://caniuse.com/mdn-api_cssstylesheet_cssstylesheet

使用observedAttributes提取设置值的方法略有不同。。。

逻辑是这样的:

  • 创建一个基本的<template id="video-player-template"> </template>标记
  • 每次将组件重新用作<video-player>标签
  • 视频标签值是从<video-player>的标签设置代码中提取的
  • 使用从<video-player>中提取的值动态创建<video>标记对象

下面是一些可测试的代码:

<html>
<head>
<style>
</style>
</head>
<body>
<!-- 1) create template -->
<template id="video-player-template">
<slot></slot>
</template>
<!-- 2) test as Component -->
<!-- test Component #1 with video loop -->
<video-player id="vidplayer1" width="400" height="300" muted autoplay controls loop type="video/webm" 
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm" >
</video-player>
<!-- test Component #2  -->
<video-player id="vidplayer2" width="200" height="120" muted autoplay controls type="video/webm" 
src="https://www.w3schools.com/tags/movie.mp4" >
</video-player>
<!-- controller scripts -->
<script type="text/javascript">
/*
test files
> MP4:  https://www.w3schools.com/tags/movie.mp4
> WEBM: https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm"
*/
var template;
var nodes;
var shadowRoot;
customElements.define(
'video-player',
class extends HTMLElement 
{
constructor() 
{
super();
template = document.getElementById('video-player-template').content;
console.log(template)
shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(template.cloneNode(true));
}

//# get component attributes (from template tag setup)
static get observedAttributes() 
{
//# extract values from video tag template to use in output video tag
//# eg:  controls id width height muted loop autoplay ... etc
return ['src', 'id', 'width', 'height', 'controls', 'muted', 'autoplay', 'loop'];
}
//# attribute change
attributeChangedCallback(property, oldValue, newValue) 
{
if (oldValue === newValue) { return; }
else { this[ property ] = newValue; }
}
//# connect component
connectedCallback() 
{
//# component is ready to be accessed
//# generate dynamic video tag
let player_code = "";
player_code += `<video `;
if( `${ this.id }` != "undefined")
{ player_code += `id="${ this.id }" `}
if( `${ this.width }` != "undefined")
{ player_code += `width="${ this.width }" `; }
if( `${ this.height }` != "undefined")
{ player_code += `height="${ this.height }" `; }
if( `${ this.controls }` != "undefined")
{ player_code += `controls `; }
if( `${ this.muted }` != "undefined")
{ player_code += `muted `; }
if( `${ this.autoplay }` != "undefined")
{ player_code += `autoplay `; }
if( `${ this.loop }` != "undefined")
{ player_code += `loop `; }

player_code += `<source src="${ this.src }" `;

//# get TYPE for video ( because ".type" is a reserved keyword )
if( String((`${ this.src }`).indexOf(".webm")) != -1)
{ player_code += `type="video/webm" `; }
else if( String((`${ this.src }`).indexOf(".mp4")) != -1)
{ player_code += `type="video/mp4" `; }
player_code += `/> </video> `;
//# apply code of dynamic video tag (add to page)...
this.innerHTML = player_code;

}
});
</script>
</body>
</html>

最新更新