Bootstrap

【前端学习记录】vue中使用el-upload组件时,上传文件进度条没有实时更新

问题背景

今天在项目中遇到一个问题,使用el-upload组件时,上传文件进度条没有实时更新,需要手动点击一下才会更新。

原理及可尝试方案

el-upload 组件默认的进度条是通过 Ajax 请求上传文件,并且进度条通过监听 xhr.upload 的 progress 事件来实时更新。但是,有些浏览器在处理进度事件时可能会存在问题,导致进度条不会实时更新。

如果进度条没有实时更新,可以尝试使用 el-upload 组件提供的 on-progress 事件来手动更新进度条。具体做法是在 on-progress 事件处理函数中,将上传进度值赋给进度条的 percentage 属性。如下所示:

<el-upload
  action="/upload"
  :on-progress="handleUploadProgress"
>
  <el-button slot="trigger" size="small" type="primary">点击上传</el-button>
</el-upload>
methods: {
  handleUploadProgress(event, file, fileList) {
    // 计算上传进度
    const progress = Math.ceil((event.loaded / event.total) * 100);
    // 将进度赋给进度条的 percentage 属性
    file.percentage = progress;
    // 如果不使用 file.percentage 属性,而是使用 fileList 的方式更新进度条,请参考下面的代码
    // const index = fileList.findIndex(item => item.uid === file.uid);
    // fileList[index].percentage = progress;

    // 强制更新 DOM
    this.$forceUpdate();
  }
}

在 handleUploadProgress 方法中,计算上传进度并将进度赋给 file.percentage 属性。然后,使用 this.$forceUpdate() 强制更新 DOM,使进度条实时更新。

这种方法可以解决进度条不实时更新的问题,但要注意的是,在每次更新进度条时,可能会导致组件重新渲染,因此如果列表中有其他需要保留的状态,要注意在更新前先保存这些状态,以免丢失。

查文档

<el-upload
  class="upload-demo"
  action="https://jsonplaceholder.typicode.com/posts/"
  :on-progress="handleProgress"
  :on-preview="handlePreview"
  :on-remove="handleRemove"
  :before-remove="beforeRemove"
  multiple
  :limit="3"
  :on-exceed="handleExceed"
  :file-list="fileList">
  <el-button size="small" type="primary">点击上传</el-button>
  <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>

on-progress 为文件上传时的钩子,回调函数为 function(event, file, fileList),经过测试,在代码上传时,会定时触发该方法,在event中会定时更新返回的进度,但是页面上没有发生变化,判断问题的原因是dom没有更新。

最终,在handleProgress中增加this.$forceUpdate();问题解决。

this.$forceUpdate();

this.$forceUpdate() 是 Vue 实例的一个方法,用于强制刷新组件的 DOM。它会导致组件重新渲染,即使没有进行数据的改变。

在 Vue 中,组件的渲染是响应式的,当数据发生变化时,Vue 会自动更新组件的 DOM。但有时候,我们希望手动触发组件的重新渲染,即使数据没有改变。这时就可以使用 this.$forceUpdate() 方法。

this.$forceUpdate() 方法会使组件的 render 函数重新执行,生成新的 VNode,并对比新旧 VNode 的差异来更新 DOM。它会跳过组件实例的依赖追踪,直接强制刷新整个组件。

注意1: this.$forceUpdate() 方法在应用程序中一般不常用。在大多数情况下,Vue 会自动追踪响应式数据的变化并更新组件,不需要手动调用 this.$forceUpdate()。只有在某些特殊情况下,例如当组件的渲染依赖于非响应式数据或外部事件时,才需要使用它。

注意2:this.$forceUpdate() 只会触发当前组件的重新渲染,而不会影响其父组件或子组件的重新渲染。如果需要更新父组件或子组件的 DOM,应该使用相应的机制,如父子组件之间通过 prop 和事件交互。

总结一下,this.$forceUpdate() 方法是 Vue 实例上的一个方法,用于强制刷新组件的 DOM,即使数据没有改变。但一般情况下,不建议频繁使用该方法,而是依赖 Vue 的自动响应式机制来更新组件的 DOM。

;