You need to enable JavaScript to run this app. SurveyJS+TS文件上传字段如何实现上传前的自定义类型校验?
优惠活动
大模型
产品
解决方案
定价
更多

SurveyJS+TS文件上传字段如何实现上传前的自定义类型校验?

核心原因说明

SurveyJS 的文件题校验触发逻辑和值绑定机制决定了现有配置必然存在延迟:

  • 自定义表达式校验器依赖的{document}字段值,只有在文件上传成功、回调执行完成并把文件元数据写入字段后才会存在
  • 原生文件上传流程顺序为:用户选中文件 → 触发onFileUpload回调 → 调用上传API → 成功后写入字段值 → 触发表单校验
  • 这种流程下,所有自定义校验必然在API请求发出后才执行,不合法的文件会直接打到接口层。
落地实现方案

1. 在onFileUpload回调中前置执行类型校验

在回调内拿到用户选中的文件列表后,在调用上传API之前先完成扩展名校验,校验不通过直接中断流程,把错误提示绑定到当前文件题组件上,SurveyJS会自动在输入区域下方展示错误。

修改后的onFileUpload实现:

// 定义业务允许的文件扩展名集合
const ALLOWED_EXTENSIONS = ['png', 'jpg', 'jpeg', 'pdf'];

async onFileUpload(surveyInstance, options) {
  if (!options.files?.length) return;

  // 前置校验:筛选不满足类型要求的文件
  const hasInvalidFile = options.files.some((file: File) => {
    const fileExtension = file.name.split('.').pop()?.toLowerCase() || '';
    return !ALLOWED_EXTENSIONS.includes(fileExtension);
  });

  // 存在不合法文件时终止上传
  if (hasInvalidFile) {
    // 将错误绑定到当前文件题,组件会自动展示提示
    options.question.error = 'Invalid file format, please upload your document in png, jpeg or pdf format.';
    // 不调用options.callback,SurveyJS会自动清理选中的无效文件
    return;
  }

  // 校验通过后走原有上传逻辑
  const targetFile = options.files[0];
  try {
    const uploadRes: any = await this.authService.uploadFile(targetFile.name, targetFile, targetFile.type);
    options.callback(
      'success',
      options.files.map((item: File) => {
        return {
          file: item,
          content: uploadRes.code
        };
      })
    );
    // 原有a标签替换逻辑保留
    const aTags = document.querySelectorAll(`[href='${uploadRes.code}']`);
    if (aTags.length) {
      (aTags[0] as HTMLAnchorElement).href = uploadRes.documentUrl;
      (aTags[0] as HTMLAnchorElement).innerHTML = uploadRes.name;
      (aTags[0] as HTMLAnchorElement).target = '_blank';
    }
  } catch (e) {
    // 保留原有API异常的处理逻辑
    options.question.error = 'File upload failed, please retry later.';
  }
}

2. 清理冗余校验逻辑

完成前置校验后,原JSON配置中依赖自定义函数的expression校验器已经失去实际作用,可以直接从validators数组中移除,避免重复校验带来的性能损耗。
另外需要注意:JSON中配置的acceptedTypes属性仅控制浏览器原生文件选择框的格式过滤,用户可以通过拖拽、粘贴文件的方式绕过这个限制,不能完全依赖该属性做合法性校验。

3. 多文件题场景的统一拦截方案

如果表单中存在多个文件题,且每个题的允许上传类型不同,可以直接在SurveyJS全局事件中统一拦截,不需要在每个题的onFileUpload回调中重复写校验逻辑:

// 初始化Survey实例时绑定全局上传拦截事件
survey.onUploadFile.add((survey, options) => {
  // 直接读取题目配置中已定义的acceptedTypes值作为校验规则
  const allowedTypes = options.question.acceptedTypes
    ?.split(',')
    .map(type => type.trim().replace('.', '').toLowerCase()) || [];

  // 校验文件类型
  const hasInvalidFile = options.files.some(file => {
    const fileExt = file.name.split('.').pop()?.toLowerCase() || '';
    return !allowedTypes.includes(fileExt);
  });

  if (hasInvalidFile) {
    options.question.error = `Unsupported file type, allowed formats: ${options.question.acceptedTypes}`;
    // 返回false直接终止上传流程
    return false;
  }
});

这种方式下,后续调整不同题目允许的文件类型,只需要修改JSON配置中的acceptedTypes字段值即可,不需要改动任何TypeScript代码。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.02 16:45:06