使用 jQuery 定位 DOM 中的评论?

Use jQuery to Target Comments in the DOM?

我正在编写一个修改 Facebook 的浏览器扩展,运行 遇到了麻烦。 Facebook 使用 HTML 评论作为标记,例如:

<a class="UFILikeLink">
  <!-- react-text: 9 -->
    Like
  <! -- /react-text -->
</a>

我想要的是一种更改上面示例中的文本 "Like" 的方法。但是,如果我使用类似的东西:

$('.UFILikeLink').html("<!-- react-text: 9 -->Like<!-- /react-text -->");

它破坏了后续操作的对象功能。换句话说,我很确定他的意思是某些操作绑定到现有的 HTML 那里(通过 Facebook),而不是我在其位置写的 HTML 的一部分。

有什么方法可以使用 jQuery 来定位 <!-- react-text --><-- /react-text --> 之间的文本吗?以类似于 text() 更改文本的方式?这样我就不必为 a 标签覆盖 HTML。

也许对这个问题有帮助的是 a 内部的整体结构。在 Chrome devtools 中查看时,它看起来更像这样:

<a class="UFILikeLink">
  ::before
  <!-- react-text: 9 -->
    "Like"
  <! -- /react-text -->
  ::after
</a>

当我使用 HTML 替换 HTML 时:

$('.UFILikeLink').html($('.UFILikeLink').html());

::before::after 结构在那里仍然可见(它在开发工具中看起来相同)。但就 Facebook 而言,功能已损坏。

要更改文本以尽量减少对周围评论和非标准事件处理程序的干扰,您需要仅针对特定的 HTML Text 节点。

jQuery 不能很好地处理文本节点,但您可以扩展 jQuery 以适应 Facebook 的非标准标记。这可能是一个温和的 PITA,具体取决于您需要参与的程度,但这是一个入门 jQuery 扩展:

jQuery.fn.extend ( {
    changeTextJustAfterCommentTag: function (commentTag, newText) {
        return this.each (function () {
            //--- process child nodes. No recursion for now.
            for (var J = 0, L = this.childNodes.length - 1;  J < L;  J++) {
                var chldNd  = this.childNodes[J];
                if (chldNd.nodeType === Node.COMMENT_NODE  &&  chldNd.nodeValue.indexOf (commentTag) !== -1) {
                    var targText    = this.childNodes[ J + 1 ];
                    if (targText.nodeType === Node.TEXT_NODE) {
                        targText.nodeValue  = newText;
                    }
                    break;
                }
            }
        } );
    }
} );

你会像这样使用它:

$('.UFILikeLink').changeTextJustAfterCommentTag ("react-text: 9", "My new like");


显示并运行此代码片段进行现场演示:

jQuery.fn.extend ( {
    changeTextJustAfterCommentTag: function (commentTag, newText) {
        return this.each (function () {
            //--- process child nodes. No recursion for now.
            for (var J = 0, L = this.childNodes.length - 1;  J < L;  J++) {
                var chldNd  = this.childNodes[J];
                if (chldNd.nodeType === Node.COMMENT_NODE  &&  chldNd.nodeValue.indexOf (commentTag) !== -1) {
                    var targText    = this.childNodes[ J + 1 ];
                    if (targText.nodeType === Node.TEXT_NODE) {
                        targText.nodeValue  = newText;
                    }
                    break;
                }
            }
        } );
    }
} );

//--- Simulated Facebook code:
$(".UFILikeLink")[0].firstChild.facebook = "megaFubar";

$(".UFILikeLink").click ( function (zEvent) {
    zEvent.preventDefault ();
    zEvent.stopImmediatePropagation ();

    if (this.firstChild.facebook) {
        $("body").append ('<span>You like!</span> ');
    }
} );

//--- Simulate userscript:
$("#normRewrite").click ( function (zEvent) {
    $('.UFILikeLink').html ("<!-- react-text: 9 -->Oops!<!-- /react-text -->");
} );

$("#textRewrite").click ( function (zEvent) {
    $('.UFILikeLink').changeTextJustAfterCommentTag ("react-text: 9", "My new like");
} );
body {width:        96%;}
body > span {
    margin-right:   2em;
    white-space:    nowrap;
}
.UFILikeLink {
    background:     buttonface;
    border:         3px outset black;
    cursor:         pointer;
    display:        inline-block;
    padding:        1ex 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<p>Click the "Like" link, see the action. &nbsp; &nbsp; Then use the rewrite buttons and see if click still works.
</p>
<p><button id="textRewrite">Special text rewrite</button> &nbsp; <button id="normRewrite">Normal (destructive) rewrite</button>
</p>
<p><a class="UFILikeLink">
    <!-- react-text: 9 -->
        Like
    <! -- /react-text -->
</a></p>
<hr>