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

原Chrome扩展上传脚本在Angular页面失效,如何触发文件上传?

问题描述

我之前一直靠自己开发的Chrome扩展帮着往Blackboard上传文件:把文件传到扩展弹窗里,读好内容和文件名后,注入下面这段代码就行:

const file = new File([contents],filename,{"type":'text/csv'}),
    dt = new DataTransfer();
dt.items.add(file);
document.querySelector('input[type="file"]').files = dt.files;
setTimeout(function() {
    document.querySelector('input[type="submit"]').click();
},1000);

结果现在网站换成Angular框架了,这段脚本直接失效。新页面的相关HTML代码是这样的:

<div class="file-upload-container">
 <div ngf-drop="" ng-model="files" class="file-upload ng-pristine ng-valid ng-empty ng-touched" ngf-multiple="fileUpload.allowMultiple" ngf-drop-disabled="disableDrag && disableDrag()" ngf-change="fileUpload.onFileSelect($files, $file, $newFiles, $duplicateFiles, $invalidFiles, $event)" ngf-stop-propagation="!(disableDrag && disableDrag())" ngf-drag-over-class="dragClass" tabindex="-1">
  <div class="fileUploadTransclude" ng-transclude="" ng-show="fileUpload.transcludeVisible">
   <div class="columns drag-area ng-scope" ng-class="{'dropped': gradesUploadSettings.hasDroppedClass}">
    <div class="file-icon"></div>
    <div class="drag-info">
     <p bb-translate="" class="ng-scope">Drop your spreadsheet to upload</p>
     <p bb-translate="" class="ng-scope">You can upload a CSV or XLS file</p>
    </div>
   </div>
  </div>
  <div class="js-file-upload-complete" ng-attr-ready="{{!fileUpload.uploadInProgress}}" ready="true"></div>
  <div ng-show="fileUpload.fileReviewVisible" class="file-upload-review ng-hide"></div>
 </div>
 <input ngf-select="" ng-if="!fileUpload.allowMultiple" type="file" ngf-change="fileUpload.onFileSelect($files)" class="hide fileUploadInput ng-scope" analytics-id="components.directives.fileUpload.input.file"><!-- end ngIf: !fileUpload.allowMultiple -->
</div>

我没法改网站本身的HTML或JS代码,只能通过Chrome扩展注入任意JS。之前找的相关问题都不适用:

  • 一个是5年前的,前提是能改网站JS代码
  • 另一个是6年前针对AngularJS的,要求能访问angular.element(elem).scope()

请问怎么在这个新页面上触发文件上传?

解决方案

针对这种用ngf-select/ngf-drop(ng-file-upload指令)的Angular文件上传组件,可以按以下步骤模拟上传:

1. 构造文件对象并包装

和之前逻辑类似,先把内容转换成目标File对象,再用DataTransfer包装:

const file = new File([contents], filename, { type: 'text/csv' });
const dt = new DataTransfer();
dt.items.add(file);

2. 定位文件输入框并设置文件

找到页面里隐藏的那个文件输入元素:

const fileInput = document.querySelector('input.fileUploadInput[type="file"]');
if (!fileInput) {
    console.error('找不到文件上传输入框');
    return;
}
// 给输入框设置文件
fileInput.files = dt.files;

3. 触发事件并通知Angular更新

Angular不会自动检测到files属性的变化,所以要手动触发绑定的ngf-change事件,还要强制触发变更检测:

// 模拟change事件并触发
const changeEvent = new Event('change', { bubbles: true });
fileInput.dispatchEvent(changeEvent);

// 触发Angular变更检测的函数
function triggerAngularChangeDetection(element) {
    if (!window.ng) return;
    
    // 优先用NgZone触发,这是Angular推荐的方式
    const ngZone = window.ng.getZone();
    if (ngZone) {
        ngZone.run(() => {});
        return;
    }
    
    // 兼容老版本Angular,尝试获取变更检测器
    try {
        const injector = window.ng.getInjector(element);
        const cdr = injector.get(window.ng.ChangeDetectorRef);
        cdr.detectChanges();
    } catch (e) {
        console.warn('变更检测触发失败,尝试兜底方案');
        // 极端情况:触发input事件强制刷新
        const inputEvent = new Event('input', { bubbles: true });
        fileInput.dispatchEvent(inputEvent);
    }
}

triggerAngularChangeDetection(fileInput);

4. 自动触发提交(可选)

等Angular处理完文件选择逻辑后,找到提交按钮触发点击:

setTimeout(() => {
    const submitBtn = document.querySelector('input[type="submit"]');
    if (submitBtn) submitBtn.click();
}, 1200); // 延迟时间可根据页面实际加载速度调整

完整注入代码示例

function uploadFileToBlackboard(contents, filename) {
    // 构造文件
    const file = new File([contents], filename, { type: 'text/csv' });
    const dt = new DataTransfer();
    dt.items.add(file);

    // 获取输入框
    const fileInput = document.querySelector('input.fileUploadInput[type="file"]');
    if (!fileInput) {
        console.error('找不到文件上传输入元素');
        return;
    }

    // 设置文件并触发事件
    fileInput.files = dt.files;
    const changeEvent = new Event('change', { bubbles: true });
    fileInput.dispatchEvent(changeEvent);

    // 触发Angular变更检测
    function triggerAngularCD(element) {
        if (!window.ng) return;
        const ngZone = window.ng.getZone();
        if (ngZone) {
            ngZone.run(() => {});
            return;
        }
        try {
            const injector = window.ng.getInjector(element);
            const cdr = injector.get(window.ng.ChangeDetectorRef);
            cdr.detectChanges();
        } catch (e) {
            console.warn('变更检测触发失败,尝试兜底');
            const inputEvent = new Event('input', { bubbles: true });
            fileInput.dispatchEvent(inputEvent);
        }
    }

    triggerAngularCD(fileInput);

    // 自动提交
    setTimeout(() => {
        const submitBtn = document.querySelector('input[type="submit"]');
        if (submitBtn) submitBtn.click();
    }, 1200);
}

// 调用示例(替换成你的内容和文件名)
// uploadFileToBlackboard('你的CSV内容', 'grades.csv');

注意事项

  • 必须把脚本注入到页面上下文中,Chrome扩展可以用chrome.scripting.executeScript时设置world: 'MAIN'实现。
  • 先在页面控制台确认window.ng是否存在,部分Angular项目可能会隐藏这个全局对象,需要调整获取方式。
  • 延迟时间可能需要根据页面加载情况微调,确保Angular有足够时间处理文件选择逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:20:10