javascript - 将子元素添加到自定义元素
问题描述
我创建了自己的自定义元素,扩展HTLMElement
并附加了一个阴影根和样式,如下所示:
class Popover extends HTMLElement {
mode = "vertical"
constructor(){
super();
let shadow = this.attachShadow({mode: 'open'}),
style = shadow.appendChild(document.createElement("style"))
...
例如,这是一个弹出菜单。我想添加孩子并保持他们的风格。让我们想象一下我的风格是这样的
.Circle {
width: 100px;
height: 100px;
background-color: red;
border-radius: 50%;
}
我创建一个div
元素并应用这样的样式
let circle = document.createElement("div");
circle.className = "Circle";
document.body.appendChild(circle);
我的红色圆圈正确显示。我现在想将该圆圈添加到我的自定义元素中,而不是document.body
出现问题。如果我像这样将它附加到我的自定义元素中,它将不会显示(尽管它实际上在 DOM 检查器中):
let p = new Popover();
p.appendChild(circle);
document.body.append(p);
我的圈子没有显示。但是,如果我查看 DOM 检查器,圆形 div 实际上就在那里,并且还应用了 .Circle 属性。
如果我然后尝试将其附加到shadowRoot
自定义元素本身,则会显示 div,但所有属性表单.Circle
类都消失了(未应用)。
let p = new Popover();
p.shadowRoot.appendChild(circle);
document.body.append(p);
那么,如何向自定义元素添加内容并保留文档类?
解决方案
好的,我了解到:
- 附加 shadow dom 将替换任何元素子元素(它们不会显示),因此必须将子元素附加到 shadow root
- Shadow DOM 不会使用文档级样式
所以我决定重写appendChild
我的自定义元素的方法,以便附加的元素将被附加,shadowRoot
并且它的计算样式被抓取并复制到它(以下方法是我的自定义元素的一部分class
:
appendChild(element){
if (!element instanceof HTMLElement)
throw new TypeError("Expected HTMLElement");
document.body.appendChild(element); // ensure that style is rendered
let style = window.getComputedStyle(element);
element.style.cssText = style.cssText;
return this.shadowRoot.appendChild(element);
}
编辑:
由于 Firefox 中的一个旧错误,我不得不像这样更改我的代码:
appendChild(element){
if (!element instanceof HTMLElement)
throw new TypeError("Expected HTMLElement");
document.body.appendChild(element); // ensure that style is rendered
element.style.cssText = this.getComputedStyleCssText(element);
return this.shadowRoot.appendChild(element);
}
getComputedStyleCssText(element){
var cssObject = window.getComputedStyle(element),
prop,
cssText,
cssAccumulator = [];
if(cssObject.cssText != ""){
return cssObject.cssText;
}
for(prop in cssObject){
if(typeof cssObject[prop] == "string"){
cssAccumulator.push(prop + " : " + cssObject[prop]);
}
}
return cssAccumulator.join("; ");
}
学分:https ://gist.github.com/johnkpaul/1754808
编辑2: 更好的递归:
appendChild(element){
if (!element instanceof HTMLElement)
throw new TypeError("Expected HTMLElement");
document.body.appendChild(element); // ensure that style is rendered
// do it recursively
let setStyle = element => {
element.style.cssText = this.getComputedStyleCssText(element);
Array.from(element.children).forEach(child => setStyle(child));
}
setStyle(element);
return this.shadowRoot.appendChild(element);
}
getComputedStyleCssText(element){
var cssObject = window.getComputedStyle(element),
prop,
cssText,
cssAccumulator = [];
if(cssObject.cssText != ""){
return cssObject.cssText;
}
for(prop in cssObject){
if(typeof cssObject[prop] == "string"){
cssAccumulator.push(prop + " : " + cssObject[prop]);
}
}
return cssAccumulator.join("; ");
}
推荐阅读
- php - 删除字符串中的 char '"' 并在 php 中创建数组
- php - 数据库死锁尝试在多个表中保存数据时
- java - 参数文件上的 AS400 SQL 脚本返回
- html - CSS - 如何将 div 内的内容水平居中
- excel - 如何在文本(链接)上将数字增加 1 并创建具有实际数字但每个副本 +1 的新文本
- java - 通过每两个字符分隔将二进制字符串更改为整数
- sparql - 在 sparql 中查询年龄
- knockout.js - Magento 2 - observables 在常见的 knockoutjs 和 magento 2 框架中的工作方式是否有区别?
- unity3d - UI Hololens - HandDraggable 问题
- matlab - 如何计算矩阵 A 的列与矩阵 B 的列之间的相关性?