You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Apps Script操作Drive中SVG:悬停标题仅生效一个的问题求助

问题排查与解决方案

问题原因

  1. 异步请求的闭包陷阱:addTitlesJS的for循环中,google.script.run是异步操作,回调函数中的idSVG引用的是循环变量。当异步请求完成时,循环已经执行完毕,idSVG的值固定为最后一个元素的ID,导致所有回调都修改同一个元素。
  2. 不可靠的延迟等待:使用固定3秒的sleep等待SVG加载,无法保证SVG完全插入DOM后再执行addTitlesJS,可能导致元素查找失败;同时如果SVG加载更快,延迟会浪费时间。
  3. innerHTML覆盖风险:直接用innerHTML设置<title>会替换目标元素的原有子内容,若SVG圆形本身有其他子元素会丢失,且不符合SVG的结构规范(<title>应该作为子元素添加,而非覆盖全部内容)。

解决方案

1. 修复异步闭包问题,优化元素处理逻辑

修改addTitlesJS函数,使用forEach遍历元素(自带块级作用域,避免闭包陷阱),并通过创建DOM元素的方式添加<title>,而非覆盖innerHTML:

function addTitlesJS(){
  var elements = document.getElementsByClassName("cls-1");
  // 将HTMLCollection转为数组,方便forEach遍历
  Array.from(elements).forEach(element => {
    var idSVG = element.id;
    if (!idSVG) return; // 跳过无ID的元素
    google.script.run.withSuccessHandler(result => {
      // 先检查是否已有title元素,避免重复添加
      let existingTitle = element.querySelector('title');
      if (existingTitle) {
        existingTitle.textContent = result;
      } else {
        let title = document.createElementNS("http://www.w3.org/2000/svg", "title");
        title.textContent = result;
        element.appendChild(title);
      }
    }).getTitle(idSVG);
  });
}

2. 移除固定延迟,在SVG加载完成后立即处理

修改showPicture函数,去掉sleep,直接在getPicture的成功回调中插入SVG后调用addTitlesJS:

function showPicture(){
  var country = document.getElementById("country").value;
  var city = document.getElementById("city").value;
  google.script.run.withSuccessHandler(image => {
    document.getElementById("image").innerHTML = image;
    // SVG已插入DOM,立即执行标题添加逻辑
    addTitlesJS();
  }).getPicture(country,city);
}

3. (可选)批量获取标题,减少异步请求次数

多次调用google.script.run会增加网络开销,可优化为一次性获取所有需要的标题:

前端修改:

function addTitlesJS(){
  var elements = document.getElementsByClassName("cls-1");
  var ids = Array.from(elements).map(el => el.id).filter(id => id);
  if (ids.length === 0) return;
  
  google.script.run.withSuccessHandler(titleMap => {
    Array.from(elements).forEach(element => {
      var idSVG = element.id;
      if (!idSVG || !titleMap[idSVG]) return;
      
      let existingTitle = element.querySelector('title');
      if (existingTitle) {
        existingTitle.textContent = titleMap[idSVG];
      } else {
        let title = document.createElementNS("http://www.w3.org/2000/svg", "title");
        title.textContent = titleMap[idSVG];
        element.appendChild(title);
      }
    });
  }).getAllTitles(ids);
}

Apps Script后端新增函数:

function getAllTitles(ids){
  const classeur = SpreadsheetApp.getActiveSpreadsheet();
  const feuilleBDD = classeur.getSheetByName("BDD");
  var tDonnees = feuilleBDD.getRange("D2:E").getValues().filter(d=>d[0] != "");
  
  // 创建ID到标题的映射对象
  let titleMap = {};
  tDonnees.forEach(row => {
    if (ids.includes(row[0])) {
      titleMap[row[0]] = row[1];
    }
  });
  return titleMap;
}

额外说明

  • SVG的<title>元素需要在SVG命名空间下创建,所以使用document.createElementNS("http://www.w3.org/2000/svg", "title"),而非普通的createElement,否则浏览器可能无法正确识别为SVG元素。
  • 增加了对无ID元素的判断,避免无效请求;同时检查已存在的<title>元素,避免重复添加。

内容的提问来源于stack exchange,提问作者devMethodes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 17:12:34