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

HTML JavaScript delay downloading img src until node in DOM

本文关键字:直到 DOM 节点 src img JavaScript 延迟 下载 HTML      更新时间:2023-09-26

嗨,我有标记从服务器发送给我,我把它设置为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'浏览器向someurl.com发出请求。有没有一种方法可以防止这种情况,而不需要自己解析标记?如果没有其他方法,谁知道用尽可能少的代码解析标记以实现我的目标的好方法?

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

你现在可以简单地使用DOMParser对象从你的HTML字符串生成一个外部文档,而不是使用div创建你当前的document作为容器。

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;
}

演示:http://jsfiddle.net/94b7gyg9/1/

注意:在你当前的代码中,浏览器仍然会尝试下载最初在你的img节点src属性中指定的资源,即使你在JS执行结束之前改变它。在这个演示中跟踪网络事务:http://jsfiddle.net/94b7gyg9/

在更改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');
});