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

Chrome扩展中Content Script未按预期工作问题求助

问题排查与代码评估:Canvas成绩显示Chrome扩展

一、空对象/无输出问题排查

1. 选择器拼写错误

代码中使用了#assigments作为父元素选择器,但Canvas平台中作业列表的正确ID是assignments(双写n)。拼写错误直接导致无法获取目标元素,后续逻辑完全不执行,最终输出空对象。

2. DOM加载时机不匹配

Canvas是单页应用,大量内容通过动态渲染加载,DOMContentLoaded触发时,作业成绩元素可能还未被插入DOM树。依赖这个事件会导致代码执行时目标元素尚未存在。

3. 元素存在性判断逻辑错误

querySelectorAll返回的是NodeList对象,即使没有匹配到元素,if(items)也会判定为true(因为对象本身存在)。正确的判断应该是检查items.length > 0,否则空的NodeList会进入循环但无实际操作。

4. 匹配规则与权限问题

Manifest中的matches规则是https://instructure.com/courses/*,但多数学校/机构的Canvas使用自定义子域名(如school.instructure.com),这个规则无法匹配这类域名。需要修改为https://*.instructure.com/courses/*才能覆盖所有Canvas课程页面。

5. 隐藏成绩的DOM结构处理

Canvas隐藏成绩时,.grade元素可能不存在,或其文本内容为非数字(如"Hidden"),直接使用parseFloat会得到NaN,导致后续计算失效。需要添加判断逻辑处理这类情况。

二、第二版代码评估

第二版代码相比第一版有明显优化:

优点:

  • 数据结构更合理:使用嵌套对象assGrpGrades[group] = {pointsScored: 0, possiblePoints: 0}存储每个作业组的得分与总分,替代第一版的字符串拼接键名(如group + "PossiblePoints"),可读性和维护性大幅提升。
  • 循环逻辑修正:第一版中for(let group in Object.keys(assGrpGrades))的写法错误,group实际是数组索引(数字)而非作业组名称,导致无法正确访问对象属性;第二版使用for(let group in assGrpGrades)直接遍历对象键名,逻辑正确。
  • 代码更简洁:直接使用querySelectorAll("#assigments .student_assignment")获取目标元素,减少了一次DOM查询。

仍需改进的点:

  • 未修正选择器拼写错误。
  • 未处理动态加载的DOM元素。
  • 未处理parseFloat返回NaN的情况。

三、修正后的代码示例

// 监听DOM变化,等待目标元素加载
const observer = new MutationObserver((mutations) => {
  const items = document.querySelectorAll("#assignments .student_assignment");
  if (items.length === 0) return;

  let assGrpGrades = {};
  items.forEach((item) => {
    // 处理可能的隐藏成绩情况
    const gradeEl = item.querySelector(".grade");
    const possiblePointsEl = item.querySelector(".points_possible");
    const groupEl = item.querySelector(".context");

    if (!gradeEl || !possiblePointsEl || !groupEl) return;

    const pointsScored = parseFloat(gradeEl.innerText);
    const possiblePoints = parseFloat(possiblePointsEl.innerText);
    const group = groupEl.innerText.trim();

    // 过滤无效数字
    if (isNaN(pointsScored) || isNaN(possiblePoints)) return;

    if (!assGrpGrades.hasOwnProperty(group)) {
      assGrpGrades[group] = {
        pointsScored: 0,
        possiblePoints: 0
      };
    }
    assGrpGrades[group].pointsScored += pointsScored;
    assGrpGrades[group].possiblePoints += possiblePoints;
  });

  // 计算平均分
  for (let group in assGrpGrades) {
    const { pointsScored, possiblePoints } = assGrpGrades[group];
    assGrpGrades[group].averageScore = possiblePoints > 0 
      ? (pointsScored / possiblePoints).toFixed(2) 
      : 0;
  }

  console.log(assGrpGrades);
  observer.disconnect(); // 找到元素后停止监听
});

// 开始监听整个文档的DOM变化
observer.observe(document.body, { childList: true, subtree: true });

修正后的Manifest匹配规则:

{
  "name": "Grade Revealer",
  "version": "1.0.0",
  "description": "A cool extension",
  "permissions": ["storage", "tabs"],
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": ["https://*.instructure.com/courses/*"],
      "js": ["contentScript.js"]
    }
  ]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 07:15:57