rel
может иметь несколько значений, разделенных пробелами, которые вы не хотите перезаписывать (см. список ).
Используйте relList интерфейс DOM дляатрибут rel
для добавления только отсутствующих значений, поэтому, когда MutationObserver сработает, он просто пропустит эти ссылки и не перейдет в бесконечный цикл:
// process the current document
onMutation([{
addedNodes: [document.body],
}]);
// process the future modifications
const mo = new MutationObserver(onMutation);
mo.observe(document, {subtree: true, childList: true});
function onMutation(mutations) {
var links = [];
// ES5 loops with vars are still much faster in 2019,
// which is important for subtree:true, more info: https://stackoverflow.com/a/39332340
for (var i = 0; i < mutations.length; i++) {
var addedNodes = mutations[i].addedNodes;
for (var j = 0; j < addedNodes.length; j++) {
var node = addedNodes[j];
if (node.tagName === 'A' && node.target === '_blank') {
links.push(node);
} else if (node.firstElementChild && node.querySelector('a[target*="_blank"]')) {
links.push(...node.querySelectorAll('a[target*="_blank"]'));
}
}
}
for (var k = 0; k < links.length; k++) {
var link = links[k];
if (!link.relList.contains('noopener')) {
link.relList.add('noopener');
}
if (!link.relList.contains('noreferrer')) {
link.relList.add('noreferrer');
}
}
}
Или вы можете присоединить глобальный mousedown
обработчик на window
и измените по нажатой ссылке:
window.addEventListener('mousedown', e => {
const link = e.target.closest('a');
if (link) {
const {relList} = link;
if (!relList.contains('noopener')) {
relList.add('noopener');
}
if (!relList.contains('noreferrer')) {
relList.add('noreferrer');
}
}
}, true);