【发布时间】:2018-09-16 00:57:38
【问题描述】:
我想强制 UI 在事件循环周期中途更新。
Vue.nextTick
Vue.nextTick 似乎为您提供了vm.$el 的更新版本,但实际上并不会导致 UI 更新。
代码笔:https://codepen.io/adamzerner/pen/RMexgJ?editors=1010
HTML:
<div id="example">
<p>Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A"
Vue.nextTick(function () {
// vm.$el.children[0].textContent === "Value: B"
// but the UI hasn't actually updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
});
}
vm.$forceUpdate
vm.$forceUpdate 似乎根本没有做任何事情。
-
vm.$el的值似乎没有改变。 - 似乎没有更新 UI。
CodePen:https://codepen.io/adamzerner/pen/rdqpJW?editors=1010
HTML:
<div id="example">
<p>Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A"
vm.$forceUpdate();
// vm.$el.children[0].textContent === "Value: A" still
// and the UI hasn't actually updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
}
v-bind:key
v-bind:key 似乎也没有做任何事情:
-
vm.$el的值似乎没有改变。 - 似乎没有更新 UI。
Codepen:https://codepen.io/adamzerner/pen/WzadKN?editors=1010
HTML:
<div id="example">
<p v-bind:key="message">Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
// vm.$el.children[0].textContent === "Value: A"
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A" still
// and the UI hasn't actually updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
}
计算
使用计算属性as this popular answer recommends 似乎也没有做任何事情:
-
vm.$el的值似乎没有改变。 - 似乎没有更新 UI。
代码笔:https://codepen.io/adamzerner/pen/EEdoeX?editors=1010
HTML:
<div id="example">
<p>Value: {{ computedMessage }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
computed: {
computedMessage: function () {
return this.message;
},
},
methods: {
change: change
}
})
function change () {
// vm.$el.children[0].textContent === "Value: A"
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A" still
// and the UI hasn't actually updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
}
承诺(在编辑中添加)
使用 Promise 也不起作用。
代码笔:https://codepen.io/adamzerner/pen/oqaEpV?editors=1010
HTML:
<div id="example">
<p>Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
// vm.$el.children[0].textContent === "Value: A"
vm.message = 'B';
// vm.$el.children[0].textContent === "Value: A" still
// and the UI hasn't actually updated
var promise = new Promise(function (resolve, reject) {
for (var i = 0; i < 10000000; i++) {}
resolve();
});
promise.then(function () {
vm.message = 'C';
});
}
设置超时
setTimeout 是唯一可行的方法。但它只有在延迟为100 时才能始终如一地工作。当延迟为0 时,它有时会起作用,但不会始终如一地起作用。
-
vm.$el更新。 - UI 更新。
代码笔:https://codepen.io/adamzerner/pen/PRyExg?editors=1010
HTML:
<div id="example">
<p>Value: {{ message }}</p>
<button v-on:click="change()">Change</button>
</div>
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'A'
},
methods: {
change: change
}
})
function change () {
// vm.$el.children[0].textContent === "Value: A"
vm.message = 'B';
setTimeout(function () {
// vm.$el.children[0].textContent === "Value: B"
// the UI has updated
for (var i = 0; i < 10000000; i++) {}
vm.message = 'C';
}, 100);
}
问题
- 为什么
Vue.nextTick、vm.$forceUpdate、v-bind:key或计算属性不起作用? - 为什么延迟为
0时setTimeout工作不一致? -
setTimeout看起来很老套。是否有“适当”的方式来强制更新 UI?
【问题讨论】:
-
更改函数是同步的,因此按定义块。没有其他事情会发生。 setTimeout 不起作用,因为执行上下文仍然是同步函数。有一个简单的解决方案,但它取决于您的用例是否计数到 10MM。
-
您介意详细说明@RandyCasburn 的一些事情吗?关于
setTimeout内部的执行上下文,我没有访问this,所以我看不出这有什么关系。无论延迟是0还是100,执行上下文都是相同的,但是将延迟更改为100会导致setTimeout起作用。假设我的用例只是让 UI 在单击“更改”后立即显示“B”,然后在片刻之后显示“C”。您能提供您想到的简单解决方案吗? -
@RandyCasburn 这对我不起作用。
watch仅在将C分配给message后才会触发。
标签: javascript vue.js