循环连续时,DOM不会更新

时间:2018-03-26 17:50:31

标签: javascript dom vue.js

在困难周期之前分配的变量。 javascript上的值已更改。但是dom方面的价值在循环结束时发生了变化。 无法显示加载div。 当循环继续时,如何显示加载div。

var vm = new Vue({
  el: '#app',
  data: {

    loading: false,

  },
  methods: {
    run() {

      this.loading = true;
      console.log(this.loading);
      for (let i = 0; i < 1000000000; i++) {}
      this.loading = false;
      console.log(this.loading);
    },
    runWithAsync() {
      vm.loading = true;
      console.log(this.loading);
      new Promise(function(resolve, reject) {
        for (let i = 0; i < 1000000000; i++) {}
        resolve(true);
      }).then((result) => {
        vm.loading = false;
        console.log(this.loading);
      })
    },
    runWithAsyncTimeout() {
      this.loading = true;
      console.log(this.loading);
      setTimeout(function() {
        new Promise(function(resolve, reject) {
          for (let i = 0; i < 1000000000; i++) {}
          resolve(true);
        }).then((result) => {
          this.loading = false;
          console.log(this.loading);
        })
      }.bind(this), 100)
    }
  }
})
.loading {
  width: 100%;
  height: 100vh;
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <button @click="run">run</button>
  <button @click="runWithAsync">runWithAsync</button>
  <button @click="runWithAsyncTimeout">runWithAsyncTimeout</button>
  <button @click="loading = !loading">change loading</button> {{ loading }}
  <div class="loading" v-if="loading"></div>
</div>

1 个答案:

答案 0 :(得分:3)

在考虑了一段时间之后,我想出了onRender函数形式的 brillant 解决方案。

Vue有一个异步更新机制,您可以在使用Vue.nextTickvm.$nextTick(视图模型实例函数)调整数据后等待。但是这会在DOM被更改但尚未呈现之后执行回调。如果你然后requestAnimationFrame,你就会在下一次渲染之前结束。此时请求另一个动画帧将导致代码运行到下一帧渲染之前,所以最终会发生渲染:

// This is dumb.
const onRender = callback =>
    Vue.nextTick(() =>
      requestAnimationFrame(() => 
        requestAnimationFrame(callback)));

var vm = new Vue({
  el: '#app',
  data: {

    loading: false,

  },
  methods: {
    run() {
      this.loading = true;
      console.log(this.loading);
      onRender(() => {
        for (let i = 0; i < 1000000000; i++) {}
        this.loading = false;
        console.log(this.loading);
      });
    }
  }
})
.loading {
  width: 100%;
  height: 100vh;
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <button @click="run">run</button>
  <button @click="loading = !loading">change loading</button> {{ loading }}
  <div class="loading" v-if="loading"></div>
</div>

使用异步支持:

// Look at them arrows!
const onRender = (callback = () => {}) =>
  new Promise(res =>
    Vue.nextTick(() =>
      requestAnimationFrame(() => 
        requestAnimationFrame(() => res(callback())))));

var vm = new Vue({
  el: '#app',
  data: {

    loading: false,

  },
  methods: {
    async run() {
      this.loading = true;
      console.log(this.loading);
      await onRender();
      for (let i = 0; i < 1000000000; i++) {}
      this.loading = false;
      console.log(this.loading);
    }
  }
})
.loading {
  width: 100%;
  height: 100vh;
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <button @click="run">run</button>
  <button @click="loading = !loading">change loading</button> {{ loading }}
  <div class="loading" v-if="loading"></div>
</div>