如何使用 JavaScript 访问 CSS 生成的内容

IT技术 javascript css dom counter
2021-02-02 11:10:14

我使用 CSScountercontent属性生成标题和数字的编号

img.figure:after {
  counter-increment: figure;
  content: "Fig. " counter(section) "." counter(figure);
}

这(假设使用适当的浏览器)在任何图像之后给出了一个很好的标签“图 1.1”、“图 1.2”等等。

问题:我如何从 Javascript 访问它?现在的问题是双重在于我想访问任一特定计数器的当前值(在某一DOM节点)所述CSS生成的内容的值(在某一DOM节点),很明显,这两个信息。

背景:我想附加到链接回参考数字适当的数字,像这样:

<a href="#fig1">see here</h>
------------------------^ " (Fig 1.1)" inserted via JS

据我所知,归结为这个问题:我可以访问contentcounter-increment通过getComputedStyle

var fig_content = window.getComputedStyle(
                    document.getElementById('fig-a'),
                    ':after').content;

但是,这不是实时值,而是样式表中声明的值。我找不到任何接口来访问真正的实时值。在计数器的情况下,甚至没有真正的 CSS 属性可以查询。

编辑:通过 DOM 规范越来越深入地挖掘,我发现了 DOM Level 2 Style Counter interface这似乎 a) 允许访问当前计数器值,b) 至少在 Firefox 中实现。但是,我不知道如何使用它。在这个 Firebug 输出之后,我目前的方法悲惨地死去了:

// should return a DOM 2 Counter interface implementation...
window.getComputedStyle(fig_a_element, ':after')
      .getPropertyCSSValue("counter-increment")[0]
      .getCounterValue();

[Exception... "Modifications are not allowed for this document" code: "7"
 nsresult: "0x80530007 (NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR)"
 location: "http://localhost/countertest.html Line: 71"]

任何想法,如何将其变为现实,都将受到高度赞赏。

编辑 2:显然我误解了 DOM Level 2 Style 的 Counter 对象。它也没有返回当前计数器值的属性。这使得上述方法无效。

新方法:是否有可能通过 DOM 读取伪元素的内容?也就是说,我可以选择伪元素(treeWalker想到)然后得到它nodeValue吗?(如果您现在开始输入“jQuery”,请重新考虑将该术语更改为“Sizzle” ...)

4个回答

我找不到任何接口来访问真正的实时值。[柜台的]

是的。我不认为有一个。对不起。

我唯一能想到的就是遍历文档中元素之前的每个元素(包括它的:before/:after伪元素),寻找计数器并加起来有多少。

显然这很可怕。如果您打算尝试重现浏览器自己的counter机制,将它替换为您自己的基于脚本的计数器可能会更容易(并且更兼容,因为 IE<=7 缺乏计数器/内容支持)。例如。类似的东西:

<a href="#prettypicture">this</a>

<div class="counter level=0">...</div>
<img id="prettypicture" class="counter level=1" alt="ooo, pretty"/>
window.onload= function() {
    var counters= Node_getElementsByClassName(document.body, 'counter');
    var indices= [];
    for (var counteri= 0; counteri<counters.length; counteri++) {
        var counter= counters[counteri];

        var level= Element_getClassArgument(counter, 'level');
        while (indices.length<=level)
            indices.push(0);
        indices[level]++;
        indices= indices.slice(level+1);
        var text= document.createTextNode('Figure '+indices.join('.'));
        counter.parentNode.insertBefore(text, counter.nextSibling);

        if (counter.id!=='') {
            for (var linki= document.links.length; linki-->0;) {
                var link= document.links[i];
                if (
                    link.hostname===location.hostname && link.pathname===location.pathname &&
                    link.search===location.search && link.hash==='#'+counter.id
                ) {
                    var text= document.createTextNode('('+indices.join('.')+')');
                    link.parentNode.insertBefore(text, link.nextSibling);
                }
            }
        }
    }
};
看来,在理论上计数器值的接口。我想我在你回答后更新了这个问题。否则,我同意我不想遍历任意数量的元素只是为了找到它们contentcounter-incrementCSS 属性。
2021-03-22 11:10:14

读这个:

生成的内容不会改变文档树。特别是,它不会反馈给文档语言处理器(例如,用于重新解析)。


样式表中指定的内容不会成为 DOM 的一部分。

所以出于这个原因,在这种情况下getComputedStyle 将不起作用我认为唯一的方法是执行一个经典的循环, 就像下面有人描述的那样!

为什么您认为生成的内容必须成为 DOM 的一部分才能使用getComputedStyle唯一的限制getComputedStyle可能是 的计算值content是指定值,那么我们需要使用的或实际的值而不是计算值。最新的规范草案没有说明计算值应该是多少。
2021-04-01 11:10:14
“从不”是一个强烈的词。显然,有一个旧的但不够的 API 来样式化值(无法访问计数器),但正如我所说,有一个新的 API 来从 DOM 中访问样式信息:lists.w3.org/档案/公共/www-style/2010Apr/0136.html我没有失去希望,总有一天它会奏效。至于现在,我认为自写循环确实是唯一的可能。
2021-04-05 11:10:14
这有没有改变?
2021-04-10 11:10:14
对不起兄弟!但恕我直言,在这种情况下永远不会强大,只是因为您试图访问不是在 DOM 级别创建的东西!;-)
2021-04-12 11:10:14

我会将您的 css 移植到 Javascript,这使您能够获得图形标题并获得更大的浏览器覆盖率。使用 jQuery 你会做这样的事情:

$(function() {
  var section = 0;
  $(".section").each(function() {
    section++;
    var figure = 0;
    $(this).find("img.figure").each(function() {
      figure++;
      var s = "Fig. " + section + "." + figure;
      $(this).attr({alt:s}).after(s);
    });
  });
});

那么你可以这样做:

<div class="section">blabla <img id="foo" src="http://www.example.com/foo.jpg"></div>
<p>Lorem ipsum dolor sit amet <a href="#foo" class="figurereference">see here</a></p>

<script type="text/javascript">
  $(function() {
    $("a.figurereference").each(function() {
      var selector = $(this).attr("href");
      var $img = $(selector);
      var s = $(this).text() + " (" + $img.attr("alt") + ")";
      $(this).text(s);
    });
  });
</script>

虽然我同意使用 CSS 这样做会非常简洁。

我找不到任何接口来访问真正的实时值。

如果你不能从 中获得valuewindow.getComputedStyle,那似乎是不可能的。

更重要的是,虽然它可以做到,但我认为这可能是在滥用 CSS,因为此时您正在打破内容和呈现之间的障碍。

看看这个相关的问题css “Content” 属性有什么好的用途?

我不认为,我以任何方式滥用 CSS。如果我这样做了,那么 CSS 2.1 规范中的“生成的内容”一章是什么?恕我直言,这是一个风格问题,我如何标记我的身材。它不是图形本身信息的重要部分,它前面是字符串“Fig. 1.1:”。我可以标注为“1.1”或“图1”或其他任何东西,这仅仅是一种扩展子弹点(我认为,你同意,实际上只是风格)。
2021-03-18 11:10:14
实际上,我通过省略标题完全简化了上面的示例。在实际情况下,“Fig 1.1”在实际图形标题(如<p><img/><span class="caption">This is an image of Foo</span></p>)前加前缀否则,我同意你的看法,CSS 生成的内容可能会被滥用来注入语义上有意义的内容,恕我直言,这是一件坏事。
2021-03-25 11:10:14
如果它仅在列表的上下文中并且是新列表项的指示,我会同意项目符号类比;否则,这是一个标题,标题是内容。此外,无论规范怎么说,它仍然违反了内容和表示分离的想法。但是,如果这不是问题,我是谁来阻止你;)
2021-04-07 11:10:14