1
loy6491 2017-04-07 10:46:20 +08:00
既然想看到过程,就加上 setTimeout 啊
|
2
445141126 2017-04-07 10:54:32 +08:00
|
3
abcbuzhiming OP @loy6491 你是对的,也就是说如果我想看到过程,就必须设置成异步任务,让 Vue 的处理 method 函数结束才行
|
4
abcbuzhiming OP @445141126 谢谢,但是这个不是我要的,我并不是需要一个过渡效果,而是需要计算的过程
|
5
wly19960911 2017-04-07 11:29:25 +08:00
那为什么要交给 VUE 去做呢, vue 的计算属性是类似于表达式公式的,用自己的方法异步完成不好么,构造自动机自动执行输出结果如何?
我认为这种东西不要依赖框架。 |
6
ferrum 2017-04-07 11:33:29 +08:00
这不就是双向数据绑定吗,为什么直接更改会无效?楼主可以把示例发出来看看。
|
7
coolzjy 2017-04-07 11:39:17 +08:00 via iPhone
Batch Update 机制,可通过异步操作解决
|
8
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 这样? |
9
abcbuzhiming OP @wly19960911 我估计可能是需要异步,我以前以为可以在 Vue 的 method 定义的函数中同步实现。
|
10
abcbuzhiming OP @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> |
11
abcbuzhiming OP @coolzjy 其实我现在的问题是,为啥这个地方就必须是异步的呢?
|
12
abcbuzhiming OP @fszaer 你说的对,这就是我要的效果,实际的需求比这复杂的多,我只是抽象出了最简单的模型,总之就是,每次运算后立即刷新结果到页面上去,这个过程是链式过程,计算->刷新->计算->刷新->计算->刷新->......同步阻塞
|
13
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> 你试试这段代码就知道,这种计算就是瞬间完成的。所以你需要使用异步去展示这段效果。 |
14
ferrum 2017-04-07 12:13:46 +08:00
@abcbuzhiming 这个变量命名满分……
我写了个 jsfiddle ,实际上$forceUpdate 是有效的,只是变量一下子从 0 到 100 ,中间没有间隔,看不出来变化而已。 具体你可以看看[jsfiddle]( https://jsfiddle.net/6yj33wns/) |
15
maplerecall 2017-04-07 12:20:19 +08:00 via Android
这难道不该用$nextTick 么, lz 的目的就是计算一次显示一次吧, async 写法把这个加入循环就好了
|
16
coolzjy 2017-04-07 12:38:11 +08:00 via iPhone
@abcbuzhiming 在极短时间内多次修改一个变量大多数时候是「与界面无关」的,如果这时候频繁操作 DOM 则会降低渲染效率。
另一方面即使没有 Batch Update 机制,你这样在一个事件循环没多次操作 DOM 的做法也会被浏览器优化为一次渲染,而不会全部把过程显示出来。 |
17
maplerecall 2017-04-07 12:41:17 +08:00 via Android
@abcbuzhiming 你这个想法大体是没有问题的,但有两点,第一点非异步代码在执行完之前是不会刷新 dom 的,第二点电脑计算太快了,大多数显示器的刷新频率只有 60fps ,也就是每帧 16 毫秒, 16 毫秒内所做的任何改变你都是看不到的,会在下一帧才输出,可以去了解一下 requestAnimationFrame
|
18
reus 2017-04-07 12:52:25 +08:00
不用 setTimeout 还想用什么……
// 禁止点击按钮的代码放这里 let update = (n) => { if (n == 0) { // 允许点击按钮的代码放这里 return; } // 更新视图的代码放这里 setTimeout(() => update(n - 1), 200); } 根本就没 vue 什么事,它只负责显示。要什么效果,是你自己实现。不要以为用了框架,就什么都要框架帮你做。 |
19
abcbuzhiming OP @ferrum 变量名是我随便弄上去的,本身就是测试用的不要在意,其次谢谢你的范例, setTimeout 用的比我好。话说作为一个后端要理解 js 的箭头函数感觉好难啊。最后就是,其实你这个范例证明了我的判断,你可以把$forceUpdate 去掉,你就会发现,仍然会更新,因此不是$forceUpdate 本身在起效,而是异步过程在起效。这也证明了我的想法, Vue 似乎没办法在一次函数调用中 forceUpdate ,必须离开这个函数调用范围
|
20
Alexisused 2017-04-07 13:11:15 +08:00 via Android
计算一次 $nextTick 一次试试呢
|
21
abcbuzhiming OP @maplerecall 就从文档上来说,没看出 nextTick 这个方法要怎么用在我这种场景
|
22
abcbuzhiming OP @coolzjy 难道就没有一种机制强制浏览器刷新 dom 吗
|
23
wly19960911 2017-04-07 13:39:29 +08:00 via Android
@abcbuzhiming
不要用后台那套来看前台,就算可以,那么意味着这套操作执行很慢,然后如果各相同种操作呢,这只是更新页面而已,还不够复杂,工作量再大一点用户直接崩溃了。 实际上是你需要让动画堵塞-执行-堵塞,看看 async 和 generator 应该能解决。 |
24
abcbuzhiming OP @maplerecall 其实我奇怪的是这一点, 60 帧那个问题很好理解,我有做过游戏开发,但是“非异步代码执行完前不能刷新 Dom ”这点,是为什么呢,是浏览器机制限制? JavaScript 语言机制限制?因为我以前开发游戏的时候,某些引擎是可以在同步代码里强制刷新当前帧的
|
25
finian 2017-04-07 14:20:29 +08:00
@abcbuzhiming #24 Vue.js 在一次 tick 中操作一次 dom ( diff, update ...),框架就是这么设计的。如果你非要即时刷新 dom ,你就直接操作 dom ( e.g. `node.innerHTML = xxx`),但是上面的同学都提到了,这个计算很快,你是看不到变化过程的。如果你是按照 Vue.js 的套路来玩的话,要做的事情就是让这个变量以一定间隔变化(不能太快),反映到视图上就是一个变化的“动画”过程。
|
26
finian 2017-04-07 14:42:09 +08:00
|
27
yihouzenmeban 2017-04-07 14:50:11 +08:00
@ferrum #14 为什么要用 $forceUpdate 呀。。本身就是双向绑定的。。改变 data 就直接改变 view 层了诶。。(实测不用 $forceUpdate 也可以的
|
28
xmflswood 2017-04-07 14:53:02 +08:00
|
29
xmflswood 2017-04-07 14:53:36 +08:00
看看异步更新队列那一节
|
30
maplerecall 2017-04-07 14:54:22 +08:00
@abcbuzhiming 非异步代码执行完前不能刷新 dom 这点是现在浏览器共同的做法, dom 重绘的开销非常大,所以在一段非异步代码内所有的 dom 操作只有在这段代码结束后才会渲染,目前并没有浏览器提供在当前强制重绘的接口,因为没有意义, js 是单线程的,你想把每次修改都反应出来又不想阻塞主进程,那就只能把所有操作都写成异步的,但即使异步中每次操作都修改了 dom 浏览器也不会马上刷新,也会等到下一个 frame 才重绘,如果你只是不想写 setTimeout 或者回调嵌套的话就用 async 直接把异步按照同步的方法来写。
|
31
Sapp 2017-04-07 16:58:22 +08:00
实际上你修改了 他就会刷新啊,只要你加上间隔,让人眼可见不就可以了吗?这个和 vue 也没啥关系。
|
32
kaneg 2017-04-07 18:55:20 +08:00 via iPhone
Javascript 是单线程,计算方法没有退出之前 UI 是没机会更新的
|
33
445141126 2017-04-07 20:24:52 +08:00
@kaneg js 里面还是可以强制同步重新渲染的 https://gist.github.com/paulirish/5d52fb081b3570c81e3a
|
34
hst001 2017-04-07 20:30:43 +08:00
现在好多前端框架主要就是解决这个问题来提供渲染性能的,你是逆行,可行的方法每加 1 就要手动更新一次 dom
|
35
xieranmaya 2017-04-07 21:11:45 +08:00
大哥,你对 n 的操作是同步的吧??
|