如何在 Web Components 中使用子元素
How to use child elements in Web Components
我正在为教育目的构建 vanilla web 组件。这是我的自定义复选框。
class Checkbox extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({mode:'open'});
this.shadow.innerHTML = "<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path /></svg><label></label>";
this._checked = false;
this.addEventListener("click", this.onClickHandler.bind(this));
}
set checked(value) {
if(value != this._checked) {
this._checked = value;
this.update();
}
}
get checked() {
return this._checked
}
onClickHandler(event) {
this.checked = !this.checked;
}
update() {
let svg = this.shadow.querySelector("svg");
if(this._checked)
svg.querySelector("path").setAttribute("d", "M19 0h-14c-2.762 0-5 2.239-5 5v14c0 2.761 2.238 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-8.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z");
else
svg.querySelector("path").setAttribute("d", "M5 2c-1.654 0-3 1.346-3 3v14c0 1.654 1.346 3 3 3h14c1.654 0 3-1.346 3-3v-14c0-1.654-1.346-3-3-3h-14zm19 3v14c0 2.761-2.238 5-5 5h-14c-2.762 0-5-2.239-5-5v-14c0-2.761 2.238-5 5-5h14c2.762 0 5 2.239 5 5z");
}
connectedCallback() {
this.update();
if(this.hasAttribute("checked"))
this.checked = true;
else
this.checked = false;
}
}
customElements.define("yasar-checkbox", Checkbox);
我想这样用
<yasar-checkbox>MY LABEL</yasar-checkbox>
但是,MY LABEL
部分在浏览器中不可见。我想让它可见并反映通过 javascript 所做的更改。我怎样才能做到这一点?
使用影子 DOM 时,您需要 use a <slot>
to pull in the child content when you place your component into the DOM. That will place all of that content into your label. Read more about the <slot>
tag 了解它如何将子节点导入影子 DOM 组件。
在下面的示例中,我采用了您的代码并添加了一些 CSS 和 <slot>
以使其按您想要的方式工作。
class Checkbox extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({mode:'open'});
this.shadow.innerHTML = "<style>div, svg, label { vertical-align: middle;}label {display: inline-block;margin-left: 5px;</style><div><svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path /></svg><label><slot></slot></label></div>";
this._checked = false;
this.addEventListener("click", this.onClickHandler.bind(this));
}
set checked(value) {
if(value != this._checked) {
this._checked = value;
this.update();
}
}
get checked() {
return this._checked
}
onClickHandler(event) {
this.checked = !this.checked;
}
update() {
let svg = this.shadow.querySelector("svg");
if(this._checked)
svg.querySelector("path").setAttribute("d", "M19 0h-14c-2.762 0-5 2.239-5 5v14c0 2.761 2.238 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-8.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z");
else
svg.querySelector("path").setAttribute("d", "M5 2c-1.654 0-3 1.346-3 3v14c0 1.654 1.346 3 3 3h14c1.654 0 3-1.346 3-3v-14c0-1.654-1.346-3-3-3h-14zm19 3v14c0 2.761-2.238 5-5 5h-14c-2.762 0-5-2.239-5-5v-14c0-2.761 2.238-5 5-5h14c2.762 0 5 2.239 5 5z");
}
connectedCallback() {
this.update();
if(this.hasAttribute("checked"))
this.checked = true;
else
this.checked = false;
}
}
customElements.define("yasar-checkbox", Checkbox);
<yasar-checkbox>MY LABEL</yasar-checkbox>
请注意,如果您想支持盲人用户使用的屏幕阅读器,则还需要向您的组件添加其他内容以使其正常工作。
例如,您需要 support tab-index
and several aria
tags。
我正在为教育目的构建 vanilla web 组件。这是我的自定义复选框。
class Checkbox extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({mode:'open'});
this.shadow.innerHTML = "<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path /></svg><label></label>";
this._checked = false;
this.addEventListener("click", this.onClickHandler.bind(this));
}
set checked(value) {
if(value != this._checked) {
this._checked = value;
this.update();
}
}
get checked() {
return this._checked
}
onClickHandler(event) {
this.checked = !this.checked;
}
update() {
let svg = this.shadow.querySelector("svg");
if(this._checked)
svg.querySelector("path").setAttribute("d", "M19 0h-14c-2.762 0-5 2.239-5 5v14c0 2.761 2.238 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-8.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z");
else
svg.querySelector("path").setAttribute("d", "M5 2c-1.654 0-3 1.346-3 3v14c0 1.654 1.346 3 3 3h14c1.654 0 3-1.346 3-3v-14c0-1.654-1.346-3-3-3h-14zm19 3v14c0 2.761-2.238 5-5 5h-14c-2.762 0-5-2.239-5-5v-14c0-2.761 2.238-5 5-5h14c2.762 0 5 2.239 5 5z");
}
connectedCallback() {
this.update();
if(this.hasAttribute("checked"))
this.checked = true;
else
this.checked = false;
}
}
customElements.define("yasar-checkbox", Checkbox);
我想这样用
<yasar-checkbox>MY LABEL</yasar-checkbox>
但是,MY LABEL
部分在浏览器中不可见。我想让它可见并反映通过 javascript 所做的更改。我怎样才能做到这一点?
使用影子 DOM 时,您需要 use a <slot>
to pull in the child content when you place your component into the DOM. That will place all of that content into your label. Read more about the <slot>
tag 了解它如何将子节点导入影子 DOM 组件。
在下面的示例中,我采用了您的代码并添加了一些 CSS 和 <slot>
以使其按您想要的方式工作。
class Checkbox extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({mode:'open'});
this.shadow.innerHTML = "<style>div, svg, label { vertical-align: middle;}label {display: inline-block;margin-left: 5px;</style><div><svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path /></svg><label><slot></slot></label></div>";
this._checked = false;
this.addEventListener("click", this.onClickHandler.bind(this));
}
set checked(value) {
if(value != this._checked) {
this._checked = value;
this.update();
}
}
get checked() {
return this._checked
}
onClickHandler(event) {
this.checked = !this.checked;
}
update() {
let svg = this.shadow.querySelector("svg");
if(this._checked)
svg.querySelector("path").setAttribute("d", "M19 0h-14c-2.762 0-5 2.239-5 5v14c0 2.761 2.238 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-8.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z");
else
svg.querySelector("path").setAttribute("d", "M5 2c-1.654 0-3 1.346-3 3v14c0 1.654 1.346 3 3 3h14c1.654 0 3-1.346 3-3v-14c0-1.654-1.346-3-3-3h-14zm19 3v14c0 2.761-2.238 5-5 5h-14c-2.762 0-5-2.239-5-5v-14c0-2.761 2.238-5 5-5h14c2.762 0 5 2.239 5 5z");
}
connectedCallback() {
this.update();
if(this.hasAttribute("checked"))
this.checked = true;
else
this.checked = false;
}
}
customElements.define("yasar-checkbox", Checkbox);
<yasar-checkbox>MY LABEL</yasar-checkbox>
请注意,如果您想支持盲人用户使用的屏幕阅读器,则还需要向您的组件添加其他内容以使其正常工作。
例如,您需要 support tab-index
and several aria
tags。