css-selectors - <template> + querySelector 使用 :scope pseudo class works with document but not documentFragment

标签 css-selectors web-component shadow-dom documentfragment html5-template

取决于 <template> 的内容,我想将其内容包装在一个容器中,以便更容易/一致地遍历。如果内容是<style><one-other-element>在顶层,我会保留它。否则,里面的任何东西都会被包裹在 <div> 中。 .

最初我让我的代码是这样的:

var hasCtnr = template.content.querySelector(':scope > :only-child, :scope > style:first-child + :last-child') != null;

但是,我注意到它不起作用——也就是说,hasCtnr一直是 false .所以,我做了一个 reduced test case (jsfiddle) .如您所见,:scope适用于常规 DOM 元素。但是,它似乎不适用于 DocumentFragment s。 我知道这项技术是新的/实验性的,但这是一个错误还是我做错了什么?

如果我使用 jQuery,它会起作用……但我的猜测是因为 jQuery 正在手动执行某些操作。

var hasCtnr = !!$(template.content).children(':only-child, style:first-child + :last-child').length;

我只关心 Chrome/Electron顺便支持一下。

这是 jsfiddle 内联:

var nonTmplResult = document.querySelector('#non-template-result');
var tmplResult = document.querySelector('#template-result');

var grandparent = document.querySelector('#grandparent');
var parent = document.querySelector('#parent');
var child = document.querySelector('#child');

var who = grandparent.querySelector(':scope > div');
if (who === parent) {
    nonTmplResult.innerHTML = 'parent as expected, :scope worked';
} else if (who === child) {
    nonTmplResult.innerHTML = "child (unexpected), :scope didn't work";
}


var tmpl = document.querySelector('template');
var content = tmpl.content;

var proto = Object.create(HTMLElement.prototype);

var hasCtnr = content.querySelector(':scope > div'); // this and even ':scope div' results in null, 'div' results in DIV
tmplResult.innerHTML += hasCtnr == null ? "null for some reason, :scope didn't work" : hasCtnr.nodeName + ', :scope worked'; // Why is this null..?
tmplResult.innerHTML += '<br/>';

proto.createdCallback = function() {
    var clone = document.importNode(content, true);
    var root = this.createShadowRoot();
    root.appendChild(clone);
    var rootHasCtnr = root.querySelector(':scope > div'); // ':host > div' seems to work but I prefer this check to happen once (above) so createdCallback can be efficient as I'll likely have many custom elements
    tmplResult.innerHTML += rootHasCtnr == null ? "null again, :scope didn't work" : rootHasCtnr.nodeName + ', :scope worked'; // Why is this also null..?
};

document.registerElement('x-foo', { prototype: proto });
#non-template-result {
    background: red;
    color: white;
}
#template-result {
    background: green;
    color: springgreen;
}
* /deep/ * {
    margin: 10px;
    padding: 5px;
}
#grandparent {
    display: none;
}
<div id="grandparent">
    <div id="parent">
        <div id="child"></div>
    </div>
</div>

<div id="non-template-result">????</div>
<div id="template-result"></div>
<x-foo>
    <p>I should be dark golden rod with khaki text.</p>
</x-foo>

<template>
    <style>
        :host {
            background: blue;
            display: block;
        }
        :host > div > p {
            color: white;
        }
        ::content > p {
            background: darkgoldenrod;
            color: khaki;
        }
    </style>
    <div>
        <p>I should be blue with white text</p>
        <content></content>
    </div>
    
</template>

<a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components#Enabling_Web_Components_in_Firefox">Enabling Web Components in Firefox</a>

最佳答案

在声明中:

var hasCtnr = template.content.querySelector(':scope > :only-child' ) //...

... :scope伪类表示调用 querySelector() 的元素.

但是 DocumentFragment (类型为 template.content )不是元素(没有根元素,没有容器)根据定义,它的 localName属性未定义。

这就是为什么这个调用永远不会选择任何东西。

var df = document.createDocumentFragment()
df.appendChild( document.createElement( 'div' ) )
var res = df.querySelector( ':scope div' )  

console.info( 'df.localName is %s', df.localName )
console.info( 'df.querySelector( :scope div ) returns %s', res )


解决方法可能是将内容放入 <div> ,执行调用,然后关闭或使用 <div>根据结果​​。

关于css-selectors - <template> + querySelector 使用 :scope pseudo class works with document but not documentFragment,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32091848/

相关文章:

css - :host/deep/selector mean? 是什么

css - CSS 中的嵌套 CSS 选择器

javascript - 检查 Dom 元素是否为原生/无自定义元素

css - 为什么像 a[title ="home"] 这样的选择器比使用 class 慢?

javascript - Chrome 扩展程序可以访问和更改静态 HTML 资源吗?

styles - 使用链接样式阻止 shadow DOM 渲染

javascript - 通过 selenium javascriptExecutor 访问影子 DOM 元素( polymer )

javascript - <content> 标记不根据模板中的位置呈现

javascript - 当所有元素都悬停时,CSS 在悬停时更改单独的元素

jquery父选择-更有效的方法