当前位置: 代码迷 >> JavaScript >> HTML JavaScript延迟下载img src直到DOM中的节点
  详细解决方案

HTML JavaScript延迟下载img src直到DOM中的节点

热度:77   发布时间:2023-06-07 16:32:07.0

嗨,我已经从服务器发送了标记,并且将其设置为div元素的innerHTML,目的是遍历树,查找图像节点并更改其src值。 有没有办法防止原始src值被下载?

这是我在做什么

function replaceImageSrcsInMarkup(markup) {
  var div = document.createElement('div');
  div.innerHTML = markup;
  var images = div.getElementsByTagName('img');
  images.forEach(replaceSrc);
  return div.innerHTML;
}

问题是您在浏览器中就这样做了: var img = document.createElement('img'); img.src = 'someurl.com' var img = document.createElement('img'); img.src = 'someurl.com'浏览器触发对someurl.com的请求。 有没有一种方法可以避免这种情况而无需自己解析标记? 如果没有其他办法,那么有人知道一种使用尽可能少的代码来解析标记的好方法来实现我的目标吗?

我知道您已经对您的解决方案感到满意,但我认为值得为将来的用户分享一种安全的方法。

现在,您可以简单地使用从HTML字符串生成外部文档,而不必使用当前document创建的div作为容器。

DOMParser专门避免了该问题中提到的陷阱和其他威胁:甚至没有元素属性,也没有img src下载,没有JavaScript执行。

因此,就您而言,您可以放心地执行以下操作:

function replaceImageSrcsInMarkup(markup) {
    var parser = new DOMParser(),
        doc = parser.parseFromString(markup, "text/html");

    // Manipulate `doc` as a regular document
    var images = doc.getElementsByTagName('img');

    for (var i = 0; i < images.length; i += 1) {
        replaceSrc(images[i]);
    }

    return doc.body.innerHTML;
}

演示: :

注意:使用您当前的代码,即使您在JS执行结束之前进行了更改,浏览器仍会尝试下载img节点src属性中最初指定的资源。 在此演示中跟踪网络事务: :

而不是在更改img源之前,将新的标记附加到DOM,而是创建一个元素,将其设置为内部HTML,更改图像的源,然后最后将更改的标记附加到页面。

这是一个完整的示例。

<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
//function allByClass(className,parent){return (parent == undefined ? document : parent).getElementsByClassName(className);}
function allByTag(tagName,parent){return (parent == undefined ? document : parent).getElementsByTagName(tagName);}
function newEl(tag){return document.createElement(tag);}
//function newTxt(txt){return document.createTextNode(txt);}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
    byId('goBtn').addEventListener('click', onGoBtnClick, false);
}

var dummyString = "<img src='img/girl.png'/><img src='img/gfx07.jpg'/>";

function onGoBtnClick(evt)
{
    var div = newEl('div');
    div.innerHTML = dummyString;

    var mImgs = allByTag('img', div);
    for (var i=0, n=mImgs.length; i<n; i++)
    {
        mImgs[i].src = "img/murderface.jpg";
    }
    document.body.appendChild(div);
}
</script>
<style>
</style>
</head>
<body>
<button id='goBtn'>GO!</button>
</body>
</html>

您可以使用正则表达式直接解析标记字符串,以替换img src。 搜索字符串中的所有img src url,然后将其替换为新的url。

var regex = /<img[^>]+src="?([^"\s]+)"?\s*\/>/g;
var imgUrls = [];
while ( m = regex.exec( markup ) ) { 
    imgUrls.push( m[1] );   
}

imgUrls.forEach(function(url) { 
    markup = markup.replace(url,'new-url'); 
});

如果您可以访问,则另一种解决方案是将所有img src设置为空字符串,并将url放入data-src属性中。 让您的标记字符串看起来像这样的标记='';

然后将此标记设置为div.innerHTML不会触发从浏览器的任何下载。 而且您仍然可以使用常规DOM选择器对其进行解析。

div.innerHTML = markup;
var images = div.getElementsByTagName('img');
images.forEach(function(img){
    var oldSrc = img.getAttribute('data-src');
    img.setAttribute('src', 'new-url');
});
  相关解决方案