如何正确地在视觉上嵌套 HTML 自定义元素
How to properly visually nest HTML Custom Elements
我正在尝试编写一个简单的 HTML 自定义元素,用于将树放在页面上,使用的简单代码如下:
<html-tree title="root">
<tree-node title="child1">
<tree-node title="leaf1"></tree-node>
<tree-node title="leaf2"></tree-node>
</tree-node>
<tree-node title="child2">
<tree-node title="leaf3"></tree-node>
<tree-node title="leaf4"></tree-node>
</tree-node>
</html-tree>
每个元素基本上都是一个影子 dom,带有一个未命名的 <slot></slot>
用于放置子元素,所以我希望有一个漂亮的嵌套结构。相反,如果我将标准调试样式 :host>* { border:1px red solid; }
分配给这些自定义元素,每个元素都会显示在自己的行上,周围有边框,而不是将它们显示为嵌套。
如何以 CSS 很好的方式保留标记指定的嵌套?
片段:
/**
* Main tree node class
*/
class GenericNode extends HTMLElement {
constructor() {
super();
this._shadow = enrich(this.attachShadow({mode: `open`}));
this._shadow.addSlot = () => this._shadow.add(create(`slot`));
if (!this.get) {
this.get = e => this.getAttribute(e);
}
this.setupDOM(this._shadow);
}
setupDOM(shadow) {
this.setStyle(`:host>* { border:1px red solid; }`)
if (this.leadIn) this.leadIn(shadow);
shadow.addSlot();
if (this.leadOut) this.leadOut(shadow);
}
setStyle(text) {
if (!this._style) {
this._style = create(`style`, text);
this._shadow.add(this._style);
} else {
this._style.textContent = text;
}
}
}
/**
* "not the root" element
*/
class Node extends GenericNode {
constructor() {
super();
}
leadIn(shadow) {
shadow.add(create(`p`, this.get(`title`)));
}
}
// register the component
customElements.define(`tree-node`, Node);
/**
* "the root" element, identical to Node, of course.
*/
class Tree extends Node {
constructor() {
super();
}
}
// register the component
customElements.define(`html-tree`, Tree);
/**
* utility functions
*/
function enrich(x) {
x.add = e => x.appendChild(e);
x.remove = e => {
if (e) x.removeChild(e);
else e.parentNode.removeChild(e);
};
x.get = e => x.getAttribute(x);
return x;
}
function find(qs) {
return Array.from(
document.querySelectorAll(qs).map(e => enrich(e))
);
}
function create(e,c) {
let x = enrich(document.createElement(e));
x.textContent = c;
return x;
};
<html-tree title="root">
<tree-node title="child1">
<tree-node title="leaf1"></tree-node>
<tree-node title="leaf2"></tree-node>
</tree-node>
<tree-node title="child2">
<tree-node title="leaf3"></tree-node>
<tree-node title="leaf4"></tree-node>
</tree-node>
</html-tree>
原来阴影的默认样式 dom 其内容为“无”,因此要实现真正的嵌套,you need to force display:block
or be similarly explicit。
在上面的代码中,不仅仅是在:host>*
上设置边框,:host
和<slot>
也需要显式标记为块:
setupDOM(shadow) {
this.setStyle(`
:host {
display: block;
border: 1px red solid;
}
:host > slot {
display: block;
border: 1px red solid;
margin-left: 1em;
}
`);
...
}
我正在尝试编写一个简单的 HTML 自定义元素,用于将树放在页面上,使用的简单代码如下:
<html-tree title="root">
<tree-node title="child1">
<tree-node title="leaf1"></tree-node>
<tree-node title="leaf2"></tree-node>
</tree-node>
<tree-node title="child2">
<tree-node title="leaf3"></tree-node>
<tree-node title="leaf4"></tree-node>
</tree-node>
</html-tree>
每个元素基本上都是一个影子 dom,带有一个未命名的 <slot></slot>
用于放置子元素,所以我希望有一个漂亮的嵌套结构。相反,如果我将标准调试样式 :host>* { border:1px red solid; }
分配给这些自定义元素,每个元素都会显示在自己的行上,周围有边框,而不是将它们显示为嵌套。
如何以 CSS 很好的方式保留标记指定的嵌套?
片段:
/**
* Main tree node class
*/
class GenericNode extends HTMLElement {
constructor() {
super();
this._shadow = enrich(this.attachShadow({mode: `open`}));
this._shadow.addSlot = () => this._shadow.add(create(`slot`));
if (!this.get) {
this.get = e => this.getAttribute(e);
}
this.setupDOM(this._shadow);
}
setupDOM(shadow) {
this.setStyle(`:host>* { border:1px red solid; }`)
if (this.leadIn) this.leadIn(shadow);
shadow.addSlot();
if (this.leadOut) this.leadOut(shadow);
}
setStyle(text) {
if (!this._style) {
this._style = create(`style`, text);
this._shadow.add(this._style);
} else {
this._style.textContent = text;
}
}
}
/**
* "not the root" element
*/
class Node extends GenericNode {
constructor() {
super();
}
leadIn(shadow) {
shadow.add(create(`p`, this.get(`title`)));
}
}
// register the component
customElements.define(`tree-node`, Node);
/**
* "the root" element, identical to Node, of course.
*/
class Tree extends Node {
constructor() {
super();
}
}
// register the component
customElements.define(`html-tree`, Tree);
/**
* utility functions
*/
function enrich(x) {
x.add = e => x.appendChild(e);
x.remove = e => {
if (e) x.removeChild(e);
else e.parentNode.removeChild(e);
};
x.get = e => x.getAttribute(x);
return x;
}
function find(qs) {
return Array.from(
document.querySelectorAll(qs).map(e => enrich(e))
);
}
function create(e,c) {
let x = enrich(document.createElement(e));
x.textContent = c;
return x;
};
<html-tree title="root">
<tree-node title="child1">
<tree-node title="leaf1"></tree-node>
<tree-node title="leaf2"></tree-node>
</tree-node>
<tree-node title="child2">
<tree-node title="leaf3"></tree-node>
<tree-node title="leaf4"></tree-node>
</tree-node>
</html-tree>
原来阴影的默认样式 dom 其内容为“无”,因此要实现真正的嵌套,you need to force display:block
or be similarly explicit。
在上面的代码中,不仅仅是在:host>*
上设置边框,:host
和<slot>
也需要显式标记为块:
setupDOM(shadow) {
this.setStyle(`
:host {
display: block;
border: 1px red solid;
}
:host > slot {
display: block;
border: 1px red solid;
margin-left: 1em;
}
`);
...
}