在 Vue2 里如何实现“一边计算,一边更新页面元素”这样的功能

2017-04-07 10:38:56 +08:00
 abcbuzhiming
我估计应该是我想的方向不太对,放狗了好久也没找到答案。实际效果并不复杂,页面上有一个按钮和一个简单的数字 v-text ,点击按钮,按钮绑定的方法会把一个变量累加 n 次,要求每累加一次,页面就更新一次并显示出来,然而实际操作发现不行,按钮绑定的 method 会把 n 一次累加完,然后页面才会刷新显示出来,因此我看不到累加过程,只能看到最终结果,最开始发现 Vue2 有一个$forceUpdate()方法能强制刷新,但是实际使用毫无效果
7337 次点击
所在节点    JavaScript
35 条回复
loy6491
2017-04-07 10:46:20 +08:00
既然想看到过程,就加上 setTimeout 啊
445141126
2017-04-07 10:54:32 +08:00
abcbuzhiming
2017-04-07 11:22:30 +08:00
@loy6491 你是对的,也就是说如果我想看到过程,就必须设置成异步任务,让 Vue 的处理 method 函数结束才行
abcbuzhiming
2017-04-07 11:23:09 +08:00
@445141126 谢谢,但是这个不是我要的,我并不是需要一个过渡效果,而是需要计算的过程
wly19960911
2017-04-07 11:29:25 +08:00
那为什么要交给 VUE 去做呢, vue 的计算属性是类似于表达式公式的,用自己的方法异步完成不好么,构造自动机自动执行输出结果如何?

我认为这种东西不要依赖框架。
ferrum
2017-04-07 11:33:29 +08:00
这不就是双向数据绑定吗,为什么直接更改会无效?楼主可以把示例发出来看看。
coolzjy
2017-04-07 11:39:17 +08:00
Batch Update 机制,可通过异步操作解决
fszaer
2017-04-07 11:44:49 +08:00
@ferrum
大概是这个意思吧
如果在方法中
const setNumber=()=>{
data.s=1;
data.s=2;
data.s=3;
}
方法执行后绑定的 s 属性显示的是 3 ,而 po 希望 显示出 1,2,3 这样?
abcbuzhiming
2017-04-07 11:47:55 +08:00
@wly19960911 我估计可能是需要异步,我以前以为可以在 Vue 的 method 定义的函数中同步实现。
abcbuzhiming
2017-04-07 11:50:35 +08:00
@ferrum 代码如下,我估计我个人还是没理解 Vue 的思路造成的,或者 Vue 并不允许在定义的函数结束前进行 re-render

<div id="group-send-sms">

<span v-text="bianliang"></span>
<input v-on:click="test" type="button" value="测试" />



</div>

<script type="text/javascript">
var vm = new Vue({
el: "#group-send-sms",
data: {

bianliang:0,
},
computed: {

},
methods: {
add:function(){
this.bianliang += 1;
},
//点击按钮,循环 100 次,每次都渲染到页面上去
test: function () {
for(var i=0;i<100;i++){
this.bianliang += 1;
this.$forceUpdate(); //这个强制渲染是无效的,并不能让循环中 bianliang 的改变立即出现在页面上
}

},
},

});

</script>
abcbuzhiming
2017-04-07 11:51:25 +08:00
@coolzjy 其实我现在的问题是,为啥这个地方就必须是异步的呢?
abcbuzhiming
2017-04-07 11:53:10 +08:00
@fszaer 你说的对,这就是我要的效果,实际的需求比这复杂的多,我只是抽象出了最简单的模型,总之就是,每次运算后立即刷新结果到页面上去,这个过程是链式过程,计算->刷新->计算->刷新->计算->刷新->......同步阻塞
wly19960911
2017-04-07 12:07:43 +08:00
你这个代码,没有时间怎么看得出来,这种一瞬间计算的东西就算是浏览器处理也是一瞬间的事情,你需要用动画的方式去处理,用 generator 或者 setTimeout (我感觉 setTimeout 太麻烦了)

<div id="test"></div>
<script>
function test() {
var node = document.getElementById('test');
for(let a = 0 ; a < 100 ; a ++) {
node.innerHTML = a;
}
}
</script>

你试试这段代码就知道,这种计算就是瞬间完成的。所以你需要使用异步去展示这段效果。
ferrum
2017-04-07 12:13:46 +08:00
@abcbuzhiming 这个变量命名满分……

我写了个 jsfiddle ,实际上$forceUpdate 是有效的,只是变量一下子从 0 到 100 ,中间没有间隔,看不出来变化而已。

具体你可以看看[jsfiddle]( https://jsfiddle.net/6yj33wns/)
maplerecall
2017-04-07 12:20:19 +08:00
这难道不该用$nextTick 么, lz 的目的就是计算一次显示一次吧, async 写法把这个加入循环就好了
coolzjy
2017-04-07 12:38:11 +08:00
@abcbuzhiming 在极短时间内多次修改一个变量大多数时候是「与界面无关」的,如果这时候频繁操作 DOM 则会降低渲染效率。
另一方面即使没有 Batch Update 机制,你这样在一个事件循环没多次操作 DOM 的做法也会被浏览器优化为一次渲染,而不会全部把过程显示出来。
maplerecall
2017-04-07 12:41:17 +08:00
@abcbuzhiming 你这个想法大体是没有问题的,但有两点,第一点非异步代码在执行完之前是不会刷新 dom 的,第二点电脑计算太快了,大多数显示器的刷新频率只有 60fps ,也就是每帧 16 毫秒, 16 毫秒内所做的任何改变你都是看不到的,会在下一帧才输出,可以去了解一下 requestAnimationFrame
reus
2017-04-07 12:52:25 +08:00
不用 setTimeout 还想用什么……

// 禁止点击按钮的代码放这里
let update = (n) => {
if (n == 0) {
// 允许点击按钮的代码放这里
return;
}
// 更新视图的代码放这里
setTimeout(() => update(n - 1), 200);
}

根本就没 vue 什么事,它只负责显示。要什么效果,是你自己实现。不要以为用了框架,就什么都要框架帮你做。
abcbuzhiming
2017-04-07 13:09:47 +08:00
@ferrum 变量名是我随便弄上去的,本身就是测试用的不要在意,其次谢谢你的范例, setTimeout 用的比我好。话说作为一个后端要理解 js 的箭头函数感觉好难啊。最后就是,其实你这个范例证明了我的判断,你可以把$forceUpdate 去掉,你就会发现,仍然会更新,因此不是$forceUpdate 本身在起效,而是异步过程在起效。这也证明了我的想法, Vue 似乎没办法在一次函数调用中 forceUpdate ,必须离开这个函数调用范围
Alexisused
2017-04-07 13:11:15 +08:00
计算一次 $nextTick 一次试试呢

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/353142

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX