【发布时间】:2021-03-20 08:48:56
【问题描述】:
我有一个自定义的 Vue 组件 ProgressBar,它显示了一个进度条。它正在通过调用setProgress 函数通过父组件进行更新。
组件由父级有条件地渲染。
当ProgressBar 组件第一次创建/渲染时,一切都按预期工作,但当它第二次渲染时,尽管data 属性发生了变化,但它不再更新。
摘自父组件:
<ProgressBar
v-if="downloadInProgress"
ref="progressBar"
type="download"
:onDone="onDownloadFinished"
:onCancel="onCancel"
style="width: 80%"
></ProgressBar>
ProgressBar组件
<template>
<div class="progress-bar-container">
<div class="progress-bar-label">
<div style="text-align: left">{{ progressText }}</div>
<div v-if="cancelable.includes(type)" class="cancel-button">
<button v-if="!done" class="link" @click="onCancel">Cancel</button>
</div>
</div>
<div class="progress-bar">
<vue-progress-bar></vue-progress-bar>
</div>
</div>
</template>
<script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */
import { defineComponent, PropType } from "vue"
type Actions = "scan" | "download"
const actionText: Record<Actions, string> = {
scan: "Scanning",
download: "Downloading",
}
export default defineComponent({
props: {
type: {
type: String as PropType<Actions>,
required: true,
},
onDone: {
type: Function,
required: false,
default: () => {},
},
onCancel: {
type: Function,
required: false,
default: () => {},
},
},
data() {
return {
total: -1,
completed: 0,
errors: 0,
progress: 0,
done: false,
cancelable: ["download"],
$Progress: this.$Progress as any,
progressText: "",
}
},
methods: {
setProgressText() {
let progressText = [
`${actionText[this.type]}...`,
`${this.completed}/${this.total !== -1 ? this.total : "?"}`,
`${this.errors > 0 ? `(${this.errors} Error(s))` : ""}`,
].join(" ")
if (this.progress === 100) {
progressText = "Done!"
}
this.progressText = progressText
},
setProgress(total: number, completed = 0, errors = 0) {
this.total = total
this.completed = completed
this.errors = errors
if (this.total === 0) {
// Handle edge case (eg. empty folders)
this.progress = 100
} else {
this.progress = Math.ceil((this.completed / this.total) * 100) || 5
}
this.$Progress.set(this.progress)
if (this.progress === 100) {
this.done = true
this.onDone()
}
this.setProgressText()
},
resetProgress() {
this.total = -1
this.completed = 0
this.errors = 0
this.progress = 0
this.done = false
// Set a small number to make something visible
this.$Progress.set(5)
},
},
created() {
this.resetProgress()
this.setProgressText()
},
})
</script>
尽管$data 对象发生了变化,但显示的progressText 保持不变并呈现默认值“正在下载... 0/?”。
在第一次渲染时一切正常,但在第二次渲染时它停止工作/更新并且文本没有得到更新。
有人知道发生了什么吗?
Vue 版本:3.0.7
编辑:
父组件中更新进度条的代码:
created() {
const messageListener: browser.runtime.onMessageEvent = async (message: object) => {
const { command } = message as Message
if (command === "download-progress") {
const { completed, total, errors } = message as DownloadProgressMessage
if (this.progressBarRef) {
this.progressBarRef.setProgress(total, completed, errors)
}
}
}
browser.runtime.onMessage.addListener(messageListener)
}
解决方案:
this.progressBarRef 是一个返回 this.$refs.progressBar as any 的计算属性。
删除此计算属性并始终访问 this.$refs.progressBar 直接解决了该问题。
非常感谢@Michal Levý 为我指明了这个方向!
【问题讨论】:
-
哪种方法不起作用,您只提到了一种更新方法,即调用
this.$Progress.set(this.progress),并且在问题的最后,您提到始终有效..您的问题不清楚其他方法用于更新。 -
@MatJ 唯一不起作用的是渲染的
progressText在第二次创建时没有得到更新,尽管setProgress()函数修改了这个值。我已经尝试将其添加为计算属性或调用$forceUpdate(),但没有任何效果。 -
progressBarRef是什么? -
一个返回
this.$refs.progressBar as any的计算属性
标签: vue.js