:host-context 在 Lit-Element Web 组件中没有按预期工作
:host-context not working as expected in Lit-Element web component
我有两个 Lit-element 网络组件 - 一个是 units-list
,其中包含许多 units-list-item
元素。 units-list-item
元素有两种不同的显示模式:紧凑型和详细型。因为列表元素支持无限滚动(因此可以包含数千个单位),所以我们需要任何在两种模式之间切换的机制以尽可能提高性能。
这就是为什么我认为一个理想的解决方案是在 units-list-item
元素的样式中使用 :host-context()
伪选择器,因为这样每个 units-list-item
元素都可以在两种显示模式只需更改应用于祖先的 class(这将在 units-list
元素的阴影 DOM 内)。
为了详细说明,这里是 units-list
元素中的相关标记。请注意,"trigger" classes 正在应用于 #list-contents
div,它是 units-list
模板的一部分。
<div id="list-contents" class="${showDetails ? 'detail-view table' : 'compact-view table'}">
${units.map(unit => html`<units-list-item .unit="${unit}"></units-list-item>`)}
</div>
如您所见,showDetails
标志控制是否将 "detail-view" 或 "compact-view" class 应用于包含所有 units-list-item
个元素。这些 classes 肯定被正确应用了。
这是 units-list-item
元素的完整渲染方法(删除了不必要的标记):
render() {
const {unit} = this;
// the style token below injects the processed stylesheet contents into the template
return html`
${style}
<div class="row compact">
<!-- compact row markup here -->
</div>
<div class="row detail">
<!-- detail row markup here -->
</div>
`;
}
然后我在 units-list-item
元素的样式中有以下内容(我们使用的是 SCSS,所以单行注释不是问题):
// This SHOULD hide the compact version of the row when the
// unit list has a "detail" class applied
:host-context(.detail-view) div.row.compact {
display: none !important;
}
// This SHOULD hide the detail version of the row when the
// unit list has a "compact" class applied
:host-context(.compact-view) div.row.detail {
display: none !important;
}
我对 :host-context 选择器的理解表明这应该有效,但是 Chrome 每次都只呈现该行的两个版本,并且 Chrome 开发工具显示选择器是从不匹配任何一行。
我知道有几个可行的替代方案,但这是我所知道的唯一一个允许整个单位列表通过更改父元素上的单个 class 来切换模式的方案.我考虑过的所有其他解决方案至少需要更新列表中每个 units-list-item
元素的 class 属性。如果可能的话,我想避免这种情况。
当然,如果可能的话,我最关心的只是让这项工作成功,但我也对一些事情感到好奇,但找不到任何关于它们的信息。我似乎找不到答案的两个问题是
- 当
:host-context
用于本身是影子 DOM 一部分的元素时,它是否认为父元素的影子 DOM 是 "host context",还是跳转 "all the way out" 到文档 DOM?
- 如果是前者,会不会
:host-context
跳过多个阴影DOM边界?假设我有一个包含自定义 list
元素的自定义 page
元素,该元素本身包含许多自定义 item
元素。如果那个 item
元素有一个 :host-context
规则,浏览器是否会首先向上扫描 list
元素的阴影 DOM,然后,如果没有匹配,向上扫描阴影 DOM 的 page
元素,如果仍然没有匹配,则向上扫描主文档 DOM 到 <html>
标签?
There is no support for :host-context
in FireFox or Safari
last update from a month ago is both Mozilla and Apple are not going to implement it.
Looks like it is going to be removed from the spec:
https://github.com/w3c/csswg-drafts/issues/1914
One alternative is to use CSS Properties (those trickle down into
shadowDOM)
JSFiddle:https://jsfiddle.net/CustomElementsExamples/jb6c81ou/
- 对 Chrome 和 Edge
使用 host-context
- 为其他浏览器使用 CSS 属性
2022 年 2 月更新
苹果改变了主意;现在在 Safari TP
如 Danny Engelman 所说,使用 css 属性来实现目标的示例
customElements.define('list-item', class extends HTMLElement {
constructor() {
const style = document.createElement('style');
const divcompact = document.createElement('div');
divcompact.innerHTML = "compact";
divcompact.className = "compact";
const divdetail = document.createElement('div');
divdetail.innerHTML = "detail";
divdetail.className = "detail";
let shadow = super().attachShadow({
mode: 'open'
});
shadow.append(style, divcompact, divdetail);
style.innerHTML = `
.compact {
background-color: red;
display: var(--display-compact, block);
}
.detail {
background-color: green;
display: var(--display-detail, block);
}
`
}
});
.compact-view {
--display-detail: none;
}
.detail-view {
--display-compact: none;
}
.box {
width: 200px;
height: 50px;
border: solid 1px black;
margin: 5px;
}
<div class="box">
no class applied
<list-item>test</list-item>
</div>
<div class="compact-view box">
compact view
<list-item>test</list-item>
</div>
<div class="detail-view box">
detail view
<list-item>test</list-item>
</div>
我有两个 Lit-element 网络组件 - 一个是 units-list
,其中包含许多 units-list-item
元素。 units-list-item
元素有两种不同的显示模式:紧凑型和详细型。因为列表元素支持无限滚动(因此可以包含数千个单位),所以我们需要任何在两种模式之间切换的机制以尽可能提高性能。
这就是为什么我认为一个理想的解决方案是在 units-list-item
元素的样式中使用 :host-context()
伪选择器,因为这样每个 units-list-item
元素都可以在两种显示模式只需更改应用于祖先的 class(这将在 units-list
元素的阴影 DOM 内)。
为了详细说明,这里是 units-list
元素中的相关标记。请注意,"trigger" classes 正在应用于 #list-contents
div,它是 units-list
模板的一部分。
<div id="list-contents" class="${showDetails ? 'detail-view table' : 'compact-view table'}">
${units.map(unit => html`<units-list-item .unit="${unit}"></units-list-item>`)}
</div>
如您所见,showDetails
标志控制是否将 "detail-view" 或 "compact-view" class 应用于包含所有 units-list-item
个元素。这些 classes 肯定被正确应用了。
这是 units-list-item
元素的完整渲染方法(删除了不必要的标记):
render() {
const {unit} = this;
// the style token below injects the processed stylesheet contents into the template
return html`
${style}
<div class="row compact">
<!-- compact row markup here -->
</div>
<div class="row detail">
<!-- detail row markup here -->
</div>
`;
}
然后我在 units-list-item
元素的样式中有以下内容(我们使用的是 SCSS,所以单行注释不是问题):
// This SHOULD hide the compact version of the row when the
// unit list has a "detail" class applied
:host-context(.detail-view) div.row.compact {
display: none !important;
}
// This SHOULD hide the detail version of the row when the
// unit list has a "compact" class applied
:host-context(.compact-view) div.row.detail {
display: none !important;
}
我对 :host-context 选择器的理解表明这应该有效,但是 Chrome 每次都只呈现该行的两个版本,并且 Chrome 开发工具显示选择器是从不匹配任何一行。
我知道有几个可行的替代方案,但这是我所知道的唯一一个允许整个单位列表通过更改父元素上的单个 class 来切换模式的方案.我考虑过的所有其他解决方案至少需要更新列表中每个 units-list-item
元素的 class 属性。如果可能的话,我想避免这种情况。
当然,如果可能的话,我最关心的只是让这项工作成功,但我也对一些事情感到好奇,但找不到任何关于它们的信息。我似乎找不到答案的两个问题是
- 当
:host-context
用于本身是影子 DOM 一部分的元素时,它是否认为父元素的影子 DOM 是 "host context",还是跳转 "all the way out" 到文档 DOM? - 如果是前者,会不会
:host-context
跳过多个阴影DOM边界?假设我有一个包含自定义list
元素的自定义page
元素,该元素本身包含许多自定义item
元素。如果那个item
元素有一个:host-context
规则,浏览器是否会首先向上扫描list
元素的阴影 DOM,然后,如果没有匹配,向上扫描阴影 DOM 的page
元素,如果仍然没有匹配,则向上扫描主文档 DOM 到<html>
标签?
There is no support for
:host-context
in FireFox or Safari
last update from a month ago is both Mozilla and Apple are not going to implement it.
Looks like it is going to be removed from the spec: https://github.com/w3c/csswg-drafts/issues/1914
One alternative is to use CSS Properties (those trickle down into shadowDOM)
JSFiddle:https://jsfiddle.net/CustomElementsExamples/jb6c81ou/
- 对 Chrome 和 Edge 使用
- 为其他浏览器使用 CSS 属性
host-context
2022 年 2 月更新
苹果改变了主意;现在在 Safari TP
如 Danny Engelman 所说,使用 css 属性来实现目标的示例
customElements.define('list-item', class extends HTMLElement {
constructor() {
const style = document.createElement('style');
const divcompact = document.createElement('div');
divcompact.innerHTML = "compact";
divcompact.className = "compact";
const divdetail = document.createElement('div');
divdetail.innerHTML = "detail";
divdetail.className = "detail";
let shadow = super().attachShadow({
mode: 'open'
});
shadow.append(style, divcompact, divdetail);
style.innerHTML = `
.compact {
background-color: red;
display: var(--display-compact, block);
}
.detail {
background-color: green;
display: var(--display-detail, block);
}
`
}
});
.compact-view {
--display-detail: none;
}
.detail-view {
--display-compact: none;
}
.box {
width: 200px;
height: 50px;
border: solid 1px black;
margin: 5px;
}
<div class="box">
no class applied
<list-item>test</list-item>
</div>
<div class="compact-view box">
compact view
<list-item>test</list-item>
</div>
<div class="detail-view box">
detail view
<list-item>test</list-item>
</div>