js获取 DOM 里所有图片(包括背景和iframe)

直接获取所有的img图片

// 获取网页中所有的img标签的图片
// 返回一个包含图片的src,宽度和高度的对象数组
function getImgs (doc) {
  return Array.from(doc.getElementsByTagName('img')) // 转换 NodeList 到数组
    .map(img => ({
      src: img.currentSrc, // 使用img.src来获取图片的原始src
      width: img.naturalWidth,
      height: img.naturalHeight
    }))
}

console.log(getImgs(document));

使用document.images获取图片

// 与上一个函数类似,但使用document.images来获取所有的img标签
function getImgs (doc) {
  return Array.from(doc.images)
    .map(img => ({
      src: img.currentSrc,
      width: img.naturalWidth,
      height: img.naturalHeight
    }))
}

console.log(getImgs(document));

获取背景图片

/**
 * 获取文档中所有DOM元素的background-image属性值。
 * @param {Document} doc - 需要查询的文档对象,通常是document。
 * @returns {string[]} - 背景图片URL的数组。
 */
function getBgImgs(doc) {
  // 定义一个正则表达式来匹配CSS中的background-image属性值。
  // 该正则可以捕获格式为url("path/to/image")中的路径字符串。
  const srcChecker = /url\(\s*?['"]?\s*?(\S+?)\s*?["']?\s*?\)/i;

  // 返回从文档中查询到的所有DOM元素的结果。
  return Array.from(
    Array.from(doc.querySelectorAll('*')) // 查询文档中的所有DOM元素。
      .reduce((collection, node) => {     // 使用reduce方法,将所有背景图片的URL聚合到一个Set中,以消除重复项。
        // 使用window.getComputedStyle方法获取节点的所有计算后的CSS样式。
        let prop = window.getComputedStyle(node, null)
          .getPropertyValue('background-image'); // 从样式中获取background-image属性值。
        let match = srcChecker.exec(prop);      // 使用正则表达式匹配background-image的属性值。
        if (match) {
          collection.add(match[1]);             // 如果匹配成功,将图片URL添加到集合中。
        }
        return collection;                      // 返回集合,供下一次迭代使用。
      }, new Set())                             // 初始化一个新的Set对象,用于收集背景图片的URL。
  );
}

// 在控制台中打印当前文档中的所有背景图片URL。
console.log(getBgImgs(document));

加载并获取背景图片的尺寸信息

// 背景图片本身不带有尺寸信息
// 这个函数将加载每一张图片并返回其尺寸
function loadImg(src, timeout = 500) {
  // 创建一个新的Promise来处理图片加载事件
  var imgPromise = new Promise((resolve, reject) => {
    let img = new Image()  // 创建一个新的Image对象
    // 图片加载成功后,调用resolve方法,并返回图片的src和其自然尺寸
    img.onload = () => {
      resolve({
        src: src,
        width: img.naturalWidth,
        height: img.naturalHeight
      })
    }
    // 如果图片加载失败,调用reject方法
    img.onerror = reject
    // 设置图片的来源
    img.src = src
  })

  // 设置一个定时器,如果超过给定的超时时间(默认500毫秒)则触发reject
  var timer = new Promise((resolve, reject) => {
    setTimeout(reject, timeout)
  })

  // 使用Promise.race返回先发生的事件,要么是图片加载完成,要么是超时
  return Promise.race([imgPromise, timer])
}

// 该函数接受一个图片URL列表,并尝试加载每一张图片
// 它将返回一个新的数组,包含成功加载的图片的信息
function loadImgAll(imgList, timeout = 500) {
  return new Promise((resolve, reject) => {
    // 使用Promise.all尝试并行加载所有图片
    // 使用map将每个图片URL转化为一个加载图片的Promise
    // 使用.catch处理每一个Promise,以确保即使某些图片加载失败,也不会使整个Promise.all失败
    Promise.all(
      imgList
        .map(src => loadImg(src, timeout))
        .map(p => p.catch(e => false))
    ).then(results => {
      // 过滤结果,移除任何加载失败的图片(它们会被标记为false)
      resolve(results.filter(r => r))
    })
  })
}

// 调用loadImgAll函数,传入一个通过getBgImgs函数获取的背景图片列表
console.log(loadImgAll(getBgImgs(document)));

在iframe中获取图片

// 递归搜索所有的iframe,并获取其中的 img>标签的图片
function searchIframes (doc) {
  var imgList = []
  doc.querySelectorAll('iframe')
    .forEach(iframe => {
      try {
        iframeDoc = iframe.contentDocument || iframe.contentWindow.document
        imgList = imgList.concat(getImgs(iframeDoc))
        imgList = imgList.concat(searchIframes(iframeDoc))
      } catch (e) {
        // 忽略因跨域引发的错误
      }
    })
  return imgList
}

console.log(searchIframes(document));

整合所有方法获取所有图片

/**
 * 获取网页上的所有图片,并返回一个包含图片的src、宽度和高度的对象数组
 * @param {Document} doc - 网页的Document对象
 * @return {Promise Array>} - 返回图片的信息数组
 */
function getImgAll(doc) {
    // 主函数返回一个Promise,用于处理图片加载
    return new Promise((resolve, reject) => {
        loadImgAll(Array.from(searchDOM(doc)))
            .then(resolve, reject)
    })

    /**
     * 从指定的DOM中搜索所有图片的src
     * @param {Document} doc - DOM文档对象
     * @return {Set string>} - 返回一个包含所有图片src的Set对象
     */
    function searchDOM(doc) {
        const srcChecker = /url\(\s*?['"]?\s*?(\S+?)\s*?["']?\s*?\)/i; // 正则用于匹配CSS背景图片的url

        // 查询所有元素,并将它们的src或background-image收集到一个Set中
        return Array.from(doc.querySelectorAll('*'))
            .reduce((collection, node) => {
                // 获取元素的计算样式
                let prop = window.getComputedStyle(node, null)
                    .getPropertyValue('background-image');
                // 使用正则检查是否有背景图片
                let match = srcChecker.exec(prop);
                if (match) {
                    collection.add(match[1]); // 如果有,添加到集合中
                }
                // 如果元素是 img>标签,添加其src到集合
                if (/^img$/i.test(node.tagName)) {
                    collection.add(node.src);
                }
                // 如果元素是 frame>标签,尝试从它的contentDocument或contentWindow.document中获取图片
                else if (/^frame$/i.test(node.tagName)) {
                    try {
                        searchDOM(node.contentDocument || node.contentWindow.document)
                            .forEach(img => {
                                if (img) {
                                    collection.add(img);
                                }
                            });
                    } catch (e) {}
                }
                return collection;
            }, new Set());
    }

    /**
     * 加载单个图片并返回其信息
     * @param {string} src - 图片的src
     * @param {number} [timeout=500] - 超时时间,默认为500毫秒
     * @return {Promise Object>} - 返回一个Promise,包含图片的信息或错误
     */
    function loadImg(src, timeout = 500) {
        // 创建一个新的Promise来处理图片加载
        var imgPromise = new Promise((resolve, reject) => {
            let img = new Image();
            img.onload = () => {
                // 当图片加载完成时,返回图片的信息
                resolve({
                    src: src,
                    width: img.naturalWidth,
                    height: img.naturalHeight
                });
            }
            img.onerror = reject; // 加载错误时拒绝Promise
            img.src = src;
        });
        // 创建一个定时器,如果在指定的超时时间内图片未完成加载,则拒绝Promise
        var timer = new Promise((resolve, reject) => {
            setTimeout(reject, timeout);
        });
        // 返回两个Promise中最先完成的一个
        return Promise.race([imgPromise, timer]);
    }

    /**
     * 加载所有图片并返回它们的信息
     * @param {Array string>} imgList - 图片src的数组
     * @param {number} [timeout=500] - 超时时间,默认为500毫秒
     * @return {Promise Array>} - 返回一个Promise,包含所有图片的信息或错误
     */
    function loadImgAll(imgList, timeout = 500) {
        return new Promise((resolve, reject) => {
            // 使用Promise.all来处理所有图片的加载
            Promise.all(
                imgList
                    .map(src => loadImg(src, timeout)) // 对每个图片src执行loadImg
                    .map(p => p.catch(e => false)) // 对于任何拒绝的Promise,返回false
            ).then(results => resolve(results.filter(r => r))); // 过滤掉所有的false值,只保留图片信息
        });
    }
}

console.log(getImgAll(document)); // 在控制台打印出从当前文档中获取的所有图片信息

posted on 2020-10-28 15:35  完美前端  阅读(3965)  评论(0)    收藏  举报

导航