如何在JS中引用:: before或:: after节点?

时间:2016-03-10 06:07:54

标签: firefox-addon firefox-developer-tools

据我所知,标准JavaScript无法获取::before::after伪元素。 Element.children不允许你这样做。

我知道必须有一种方法,至少在Chrome特权的Firefox附加代码中,因为它列出了页面中的每个::before元素(显然getComputedStyle()也适用于它,因为你可以在inspector中列出它的所有样式,用JavaScript编写。

这个API在哪里被记录下来,并且它只是在Firefox和Chrome浏览器中有所不同和特权 - 或者很快就会成为标准的东西?

4 个答案:

答案 0 :(得分:4)

CSS生成的内容不是DOM的一部分,即使你得到它们,你也无法对::before / ::after伪元素做很多事情。我能想到的唯一用例是:

  • 访问伪元素上的CSS计算值。 window.getComputedStyle()通过可选的第二个参数支持此功能。

  • 枚举生成的内容。你可以做到这一点:

    • 使用特定于浏览器的API。在Firefox中,DevTools检查器uses是一个特殊界面 - inIDeepTreeWalker
    • 或通过遍历DOM并检查(针对每个元素)其content / :before的计算样式中是否有:after。例如:

      window.getComputedStyle(elt, ':before').content
      
  • 获取CSS中定义的计数器的“实时”值,如How to access CSS generated content with JavaScript中所示 - 请参阅该问题以获取详细信息。

答案 1 :(得分:2)

至少在我看来,你的问题不明确完全你想要做什么或得到什么。

最直接等同于::before::after

如果您想要实际插入内容,这是::before::after CSS选择器所做的事情,那么最直接的等价物是Element.insertAdjacentHTML(position, text)。在那种情况下:

相当于::before

Element.insertAdjacentHTML("beforebegin", "<p>Additional HTML content before element.</p>");

相当于::after

Element.insertAdjacentHTML("afterend", "<p>Additional HTML content after element.</p>");

Element.insertAdjacentHTML()还有afterbeginbeforeend选项,可以在引用的Element的开头或结尾之前插入HTML文本。

可替换地:

您可以使用Node.insertBefore(newNode, referenceNode)插入节点 对于::before,它将是(在myNode之前插入newNode):

myNode.parentNode.insertBefore(newNode, myNode);

对于::after,它将是(在myNode之后插入newNode):

myNode.parentNode.insertBefore(newNode, myNode.nextSibling);

获取参考文献:

如果您尝试获取DOM中较早的元素的引用,那么听起来您正在寻找Node.previousSibling。如果您正在寻找对DOM中稍后元素的引用,那么您正在寻找Node.nextSibling

在DOM行走顺序中:

您也可能正在寻找Node中参考DOM walk order之前和之后的元素。但是,CSS选择器::before::after确实。但是,从你提到Page Inspector开始,听起来就像你想要的那样。如果是这样,那么您可以使用TreeWalker来遍历DOM树。

以下内容应该做你想要的(注意:目前未经测试,可能会遗漏一些东西。):

//referenceNode is the node for which we want to find the elements
//  before and after in DOM walk order.

//Create the TreeWalker
let treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT,
                                           {acceptNode: function(node) { 
                                                            return NodeFilter.FILTER_ACCEPT;
                                                        }
                                            }, 
                                            false );
//Point the TreeWalker at the referenceNode. 
treeWalker.currentNode = referenceNode;
//Get the node immediately prior to the referenceNode in DOM walk order
let thePreviousNode = treeWalker.previousNode();

//Point the TreeWalker back at the referenceNode.
treeWalker.currentNode = referenceNode;
//Get the node immediately after to the referenceNode in DOM walk order
let theNextNode = treeWalker.nextNode();

正如Nickolay所述,如果您需要页面检查器或DOM Inspectordocumentation)提供的完整详细信息,那么您需要使用inIDeepTreeWalker 。但是,您不太可能需要或不需要使用Firefox特定非标准接口提供的详细信息。如果你想要了解如何构建XUL <toolbarbutton>之类的东西(不是属性/属性,而是组成像<toolbarbutton>这样的XUL元素的XBL,你只需要它)。对于您可能正在考虑的绝大多数内容,标准的TreeWalker应该没问题。

除了inIDeepTreeWalker之外,以上所有内容都是JavaScript的标准部分,不需要提升权限(即不要求它在加载项中)。

答案 2 :(得分:0)

如果您想通过 Javascript 引用 (::before / ::after) 伪元素是因为您试图对其 CSS 进行更改,则可以通过向 main 添加一个新类来实现元素,然后在 CSS 中创建一个额外的样式,以便在您的新类应用于该元素时使用。

我将以 Stack Overflow 自己的汉堡按钮设计为例。

现场示例: https://jsfiddle.net/tb4f3zq6/5/

HTML:

<!DOCTYPE html>
<html>
<head>
  <title>Hamburger</title>
</head>
<body>

  <div class='HamburgerContainer'>
    <a class='HamburgerButton'></a>
  </div>

</body>
</html>

CSS:

.HamburgerContainer {
  display: flex;
  height: 50px;
  width: 44px;
  flex-shrink: 0;
  padding: 0;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.HamburgerButton {
  width: 18px;
  height: 2px;
  background-color: gray;
  position: relative !important;
}

.HamburgerButton::before {
  position: absolute;
  content: '';
  left: 0;
  top: 5px;
  width: 18px;
  height: 2px;
  background-color: gray;
  transition: all ease-in-out .1s;
}

.HamburgerButton::after {
  position: absolute;
  content: '';
  left: 0;
  top: -5px;
  width: 18px;
  height: 2px;
  background-color: gray;
  transition: all ease-in-out .1s;
}

/*new style after applying active class*/
.HamburgerButton.active {
  background-color: transparent;
}

.HamburgerButton.active::after,
.HamburgerButton.active::before {
  top: 0;
  transform: rotate(45deg);
}

.HamburgerButton.active::before {
  transform: rotate(-45deg);
}

JS:

const HamburgerContainer = document.getElementsByClassName('HamburgerContainer');
const HamburgerButton = document.getElementsByClassName('HamburgerButton');
let active = false;

HamburgerContainer[0].addEventListener('click', function(){ToggleHamburger();});

function ToggleHamburger(){
    if(!active)
  {
    HamburgerButton[0].classList.add('active');
    active = true;
  }
  else
  {
    HamburgerButton[0].classList.remove('active');
    active = false;
  }
}

答案 3 :(得分:-1)

您可以使用iniDOMUtils - selectorMatchesElement()功能。

您可以在此处阅读更多相关信息 - https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/inIDOMUtils#selectorMatchesElement%28%29