我正在尝试确定是否可以使用锚标记包装字符串的所有实例。
基本上我想在我们的网站上找到myBrand
或myBrand.com
的任何实例,并将它们包装在诸如<a href="/">myBrand</a>
或<a href="/">myBrand.com</a>
之类的锚点中。
但是,我希望能够找到所有此类实例,无论它们位于页面上各个元素中的深度如何,并查看它们是否已链接,这就是我遇到的问题。
// -----编辑----- //
我已经将代码段修改为现在的内容,但是仍然遇到困难
document.querySelectorAll('body').forEach(function(el){
var text = el.innerHTML.match(/myBrand/g);
console.log(text.parentElement); // how do i get the parent?
if(isAnchor(text.parentElement)){
//
}else{
var newtext = el.innerHTML.replace(/myBrand/g, '<a href="/">myBrand</a>');
el.innerHTML = newtext;
}
});
function isAnchor(str){
return /^\<a.*\>.*\<\/a\>/i.test(str);
}
<body>
myBrand
<h1>myBrand.com</h1>
<p>This is a div that mentions myBrand</p>
<table>
<thead>
<tr>
<td>This is myBrand's table header</td>
</tr>
</thead>
<tbody>
<tr>
<td>myBrand.com</td>
</tr>
</tbody>
</table>
<a href="/">myBrand.com</a>
</body>
答案 0 :(得分:1)
您可以将replace
与RegEx一起使用,以如下方式设置innerHTML
属性:
document.body.innerHTML = document.body.innerHTML.replace(/myBrand(?!\.)/g, '<a href="/">myBrand</a>');
document.body.innerHTML = document.body.innerHTML.replace(/myBrand.com/g, '<a href="/">myBrand.com</a>');
<body>
myBrand
<h1>myBrand.com</h1>
<p>This is a div that mentions myBrand</p>
<table>
<thead>
<tr>
<td>This is myBrand's table header</td>
</tr>
</thead>
<tbody>
<tr>
<td>myBrand.com</td>
</tr>
</tbody>
</table>
<a href="/">myBrand.com</a>
</body>
答案 1 :(得分:1)
使用innerHTML
替换html内容的一个问题是,一旦您使用innerHTML设置新的html,分配给现有元素的任何数据或事件都将被删除。在document.body
级别执行此操作是一个非常糟糕的主意。
因此,我写了一个使用文本节点的解决方案。文本节点不能有事件,因此删除文本节点并添加新节点不会有任何副作用(选择除外,在这种情况下我们可以忽略)。
function iterateTextNodes(container, callback) {
Array.from(container.childNodes).forEach(node => {
if (node.nodeType === node.TEXT_NODE) {
callback(node);
} else if (node.tagName !== 'A') {
/* Do not go inside anchor tags checking for text nodes,
this get rids of the problem with nodes that are already
inside anchor tags */
iterateTextNodes(node, callback);
}
});
}
function getAnchor(href, content) {
const anchor = document.createElement('A');
anchor.appendChild(document.createTextNode(content));
anchor.setAttribute('href', href);
return anchor;
}
iterateTextNodes(document.body, function (node) {
const parentNode = node.parentNode;
// Check for myBrand.com first and then check for myBrand, to handle all the cases
node.nodeValue.split('myBrand.com').forEach((string, i) => {
i && parentNode.insertBefore(getAnchor('/', 'myBrand.com'), node);
string.split('myBrand').forEach((string, i) => {
i && parentNode.insertBefore(getAnchor('/', 'myBrand'), node);
parentNode.insertBefore(document.createTextNode(string), node);
});
});
parentNode.removeChild(node);
});
<body>
myBrand
<h1>myBrand.com</h1>
<p>This is a div that mentions myBrand</p>
<table>
<thead>
<tr>
<td>This is myBrand's table header</td>
</tr>
</thead>
<tbody>
<tr>
<td>myBrand.com</td>
</tr>
</tbody>
</table>
<a href="/">myBrand.com</a>
</body>
答案 2 :(得分:0)
您可以为此使用XPath:
function textContaining(phrase) {
return document.evaluate(
"//text()[contains(., '" + phrase + "')]",
document,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
)
}
然后您可以像这样遍历结果:
var result = textContaining(phrase)
for (var i = 0; i < result.snapshotLength; ++i) {
var originalNode = result.snapshotItem(i)
// ...
}
一旦有了匹配的#text
个节点列表,您只需要过滤掉.parentElement是一个<a>
标签的节点即可。
或者,您可以使用jQuery .parents()
功能来检查父母的父母,从而解决<a><span>sometext</span></a>
之类的情况,而不仅仅是直接子女的情况。