如何在 Vue.js 和 Vuetify 中延迟大量渲染
How to delay heavy rendering in Vue.js and Vuetify
我正在使用 Vue.js 2 和 Vuetify 2.6,并且要在扩展面板中进行一些繁重的表单渲染。单击面板的 header 时,面板部分打开之前会有一小段延迟,因为我猜这是第一次渲染。延迟并没有给我带来太大的困扰,但我想在初始渲染发生时立即显示进度指示器。问题是,进度指示器仅在渲染完成后出现。不过,点击事件会立即发生,如以下代码段的 js 控制台所示。
有没有办法延迟面板部分的渲染以首先显示进度指示器?令人惊讶的是 UI 在渲染发生时没有冻结,所以进度指示器动画有效。
我无法使用扩展面板“eager”选项,因为我有很多面板,一次加载所有内容会花费太多时间。
这段代码片段用一个夸张的例子说明了这个问题。
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
loading: false
}),
methods: {
click() {
console.log('click')
this.loading = true
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.6.1/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify@2.4.4/dist/vuetify.min.css">
<v-app id="app">
<template>
<v-expansion-panels>
<v-expansion-panel @click="click">
<v-expansion-panel-header>
<template v-slot:default="{ open }">
<span>
<v-progress-circular
v-if="loading"
indeterminate
size="14"
width="2"
color="blue"
class="d-inline-block"
/>
</span>
<span>Click me! opened: {{ open }}</span>
</template>
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-text-field v-for="(item, i) in 1500" :key="i" />
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</template>
</v-app>
问题是 loading
标志更改(包括呈现微调器和面板内容)的效果发生在同一个宏标记中。
一种解决方法是将效果分成两组:(1) 切换 loading
以呈现微调器并打开面板,以及 (2) 切换一个新标志以呈现面板内容。这允许将第二个效果组移动到下一个宏标记:
添加布尔标志作为数据 属性,并有条件地使用该标志呈现面板内容。
在 click
处理程序中,等待宏滴答(即等待 setTimeout()
没有超时)。
切换第 1 步中的标志以呈现面板内容。
<script>
new Vue({
data: () => ({
1️⃣
loadTextfields: false,
}),
methods: {
async click() {
this.loading = true
2️⃣
await new Promise(r => setTimeout(r))
3️⃣
this.loadTextfields = true
}
}
})
</script>
<v-expansion-panels>
<v-expansion-panel @click="click">
⋮
<v-expansion-panel-content>
1️⃣
<template v-if="loadTextfields">
<v-text-field v-for="(item, i) in 1500" :key="i"/>
</template>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
loading: false,
loadTextfields: false,
}),
methods: {
async click() {
console.log('click')
this.loading = true
await new Promise(r => setTimeout(r))
this.loadTextfields = true
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.6.1/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify@2.4.4/dist/vuetify.min.css">
<v-app id="app">
<template>
<v-expansion-panels>
<v-expansion-panel @click="click">
<v-expansion-panel-header>
<template v-slot:default="{ open }">
<span>
<v-progress-circular
v-if="loading"
indeterminate
size="14"
width="2"
color="blue"
class="d-inline-block"
/>
</span>
<span>Click me! opened: {{ open }}</span>
</template>
</v-expansion-panel-header>
<v-expansion-panel-content>
<template v-if="loadTextfields">
<v-text-field v-for="(item, i) in 1500" :key="i"/>
</template>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</template>
</v-app>
我正在使用 Vue.js 2 和 Vuetify 2.6,并且要在扩展面板中进行一些繁重的表单渲染。单击面板的 header 时,面板部分打开之前会有一小段延迟,因为我猜这是第一次渲染。延迟并没有给我带来太大的困扰,但我想在初始渲染发生时立即显示进度指示器。问题是,进度指示器仅在渲染完成后出现。不过,点击事件会立即发生,如以下代码段的 js 控制台所示。
有没有办法延迟面板部分的渲染以首先显示进度指示器?令人惊讶的是 UI 在渲染发生时没有冻结,所以进度指示器动画有效。
我无法使用扩展面板“eager”选项,因为我有很多面板,一次加载所有内容会花费太多时间。
这段代码片段用一个夸张的例子说明了这个问题。
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
loading: false
}),
methods: {
click() {
console.log('click')
this.loading = true
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.6.1/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify@2.4.4/dist/vuetify.min.css">
<v-app id="app">
<template>
<v-expansion-panels>
<v-expansion-panel @click="click">
<v-expansion-panel-header>
<template v-slot:default="{ open }">
<span>
<v-progress-circular
v-if="loading"
indeterminate
size="14"
width="2"
color="blue"
class="d-inline-block"
/>
</span>
<span>Click me! opened: {{ open }}</span>
</template>
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-text-field v-for="(item, i) in 1500" :key="i" />
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</template>
</v-app>
问题是 loading
标志更改(包括呈现微调器和面板内容)的效果发生在同一个宏标记中。
一种解决方法是将效果分成两组:(1) 切换 loading
以呈现微调器并打开面板,以及 (2) 切换一个新标志以呈现面板内容。这允许将第二个效果组移动到下一个宏标记:
添加布尔标志作为数据 属性,并有条件地使用该标志呈现面板内容。
在
click
处理程序中,等待宏滴答(即等待setTimeout()
没有超时)。切换第 1 步中的标志以呈现面板内容。
<script>
new Vue({
data: () => ({
1️⃣
loadTextfields: false,
}),
methods: {
async click() {
this.loading = true
2️⃣
await new Promise(r => setTimeout(r))
3️⃣
this.loadTextfields = true
}
}
})
</script>
<v-expansion-panels>
<v-expansion-panel @click="click">
⋮
<v-expansion-panel-content>
1️⃣
<template v-if="loadTextfields">
<v-text-field v-for="(item, i) in 1500" :key="i"/>
</template>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
loading: false,
loadTextfields: false,
}),
methods: {
async click() {
console.log('click')
this.loading = true
await new Promise(r => setTimeout(r))
this.loadTextfields = true
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.6.1/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify@2.4.4/dist/vuetify.min.css">
<v-app id="app">
<template>
<v-expansion-panels>
<v-expansion-panel @click="click">
<v-expansion-panel-header>
<template v-slot:default="{ open }">
<span>
<v-progress-circular
v-if="loading"
indeterminate
size="14"
width="2"
color="blue"
class="d-inline-block"
/>
</span>
<span>Click me! opened: {{ open }}</span>
</template>
</v-expansion-panel-header>
<v-expansion-panel-content>
<template v-if="loadTextfields">
<v-text-field v-for="(item, i) in 1500" :key="i"/>
</template>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</template>
</v-app>