gpt4 book ai didi

javascript - 如何在 Vue.js 的事件循环中强制更新 UI?

转载 作者:搜寻专家 更新时间:2023-10-30 22:47:41 28 4
gpt4 key购买 nike

我想强制 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似乎根本没有做任何事情。

  1. 它似乎没有改变 vm.$el 的值。
  2. 它似乎没有更新 UI。

代码笔: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):键

v-bind:key也似乎根本没有做任何事情:

  1. 它似乎没有改变 vm.$el 的值。
  2. 它似乎没有更新 UI。

代码笔: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 ,似乎也没有做任何事情:

  1. 它似乎没有改变 vm.$el 的值。
  2. 它似乎没有更新 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(在编辑中添加)

使用 promises 也不起作用。

代码笔: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 时,它有时会起作用,但不能始终如一地起作用。

  1. vm.$el 更新。
  2. 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);
}

问题

  1. 为什么 Vue.nextTickvm.$forceUpdatev-bind:key 或计算属性不起作用?<
  2. 为什么当延迟为 0setTimeout 工作不一致?
  3. setTimeout 似乎很老套。是否有一种“适当”的方式来强制更新 UI?

最佳答案

概要

B 没有被更新/显示在 UI 中的错觉是由 Vue 的异步更新队列和 JavaScript 的事件循环过程模型的组合造成的。有关详细信息和证明,请继续阅读。

#调查结果总结#

这些实际上您想要的(但似乎没有)

  • Vue.nextTick
  • setTimeout -(但似乎没有短超时)

这些按预期工作(但需要解释)

  • v-bind:key
  • vm.$forceUpdate
  • promise

注意:上面的 but doesn't seem to 是承认 Vue 正在做它应该做的事情,但没有出现预期的视觉输出。因此,代码没有产生预期的输出是准确的。

讨论

前两项工作

证明前两个你想做的事很容易。 “B”不被放置在 View 中的想法将被驳斥。但需要进一步讨论以解决缺乏明显变化的问题。

  • 在 Chrome 中打开每支笔
  • 在开发工具中,在第 1789 行的 vue.js 中设置一个断点
  • 逐步完成序列

当您逐步执行该序列时,您会注意到 UI 已按应有的值“B”更新(无论超时长度如何)。驱散。

那么缺乏可见性呢?这是由 JavaScript 的 Event Loop 过程模型引起的,具体与称为 Run-to-Completion 的原则有关。 MDN Event Loop Documentation状态:

A downside of this model is that if a message takes too long tocomplete, the web application is unable to process user interactionslike click or scroll.

或运行渲染/绘制浏览器进程。因此,当堆栈被执行时,B 被渲染然后 C 紧随其后,这似乎 B 从未被渲染过。当使用带有 JavaScript 繁重任务(例如引导 SPA)的动画 GIF 时,可以看到这个确切的问题。动画 GIF 要么会断断续续,要么根本不会动画 - Run-to-Completion 挡住了路。

所以 Vue 做了它应该做的事情,而 JavaScript 做了它应该做的事情。但是长时间运行的循环很麻烦。这就是像 lodash _debounce 或简单的 setTimout 这样的工具很有用的原因。

最后三部作品?

是的。在 vue.js 中使用相同的断点将显示唯一的中断发生在 Vue 刷新其更新队列时。正如在 Vue's documentation about Async Update Queue 中讨论的那样每个更新都排队,并且只呈现每个属性的最后更新。因此,尽管 message 在处理过程中实际上更改为 B,但由于 Vue 异步队列的工作方式,它永远不会被渲染:

In case you haven’t noticed yet, Vue performs DOM updatesasynchronously. Whenever a data change is observed, it will open aqueue and buffer all the data changes that happen in the same eventloop.

关于javascript - 如何在 Vue.js 的事件循环中强制更新 UI?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49685304/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com