问题背景
今天在项目中遇到一个问题,使用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。