VueJS-发出事件-在其他计算之前显示HTML

时间:2019-08-17 12:36:36

标签: javascript vue.js

要:

在发出事件时显示HTML元素,并在显示该元素后运行一些计算。

但是:

HTML元素仅在计算运行后显示。

奇怪:

控制台显示事件回调在计算之前运行。

let app = new Vue({
  el: '#app',
  data: {
    show: false
  },

  methods: {
    showCallback() {
      console.log('showCallback');
      console.log(this.show);
      this.show = true;
      console.log(this.show);
    },
    
    start() {
      this.$emit('loading-show');

      console.log('Calculation start');

      // Do some calculations
      for (let i = 1; i < 10000000000; i++) {}

      console.log('Calculation finish');
    }
  },

  mounted() {
    this.$on('loading-show', this.showCallback);
  },

  destroyed() {
    this.$off('loading-show', this.showCallback);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <button @click="start">Start</button>
  <h1 v-show="show">Shown</h1>
</div>

2 个答案:

答案 0 :(得分:2)

  1. 您不应在测试中使用for循环,而应使用setTimeout。否则,您的用户界面将不会更新。

  2. 使用v-ifv-else-ifv-else根据您的状态显示HTML。

let app = new Vue({
  el: '#app',
  data: {
    show: false,
    done: false,
    
    showCallback: function() {
      console.log('showCallback');
      console.log(this.show);
      this.show = true;
      console.log(this.show);
    }
  },

  methods: {
    start() {
      this.done = false
      this.$emit('loading-show');

      console.log('Calculation start');

      // Do some calculations
      setTimeout(()=>{
        this.done = true
        console.log('Calculation finish');}, 2000)      
    }
  },

  mounted() {
    this.$on('loading-show', this.showCallback);
  },

  destroyed() {
    this.$off('loading-show', this.showCallback);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <button @click="start">Start</button>
  <h1 v-if=!show>Press Start</h1>
  <h1 v-else-if="!done">Processing</h1>
  <h1 v-else>Shown</h1>
</div>

答案 1 :(得分:0)

await vm.$nextTick();-然后给浏览器喘口气

  • 带有双requestAnimationFrame

发出事件后,更新dom,并在进行任何形式的阻塞之前跳过渲染帧。

应该总是做-考虑到低计算设备。

Vue.skipFrame = function(){

  return new Promise(resolve => {
    requestAnimationFrame(() => 
    requestAnimationFrame(resolve)
    )
  })
}

let app = new Vue({
  el: '#app',
  data: {
    show: false
  },

  methods: {
    showCallback(ctx) {
      console.log('showCallback');
      console.log(this.show);
      this.show = true;
      console.log(this.show);
    },
    
    async start() {
      this.$emit('loading-show', this);
      console.log('Calculation start');
      await this.$nextTick();
      // dom is up to date now and has to be painted
      // thus skip one frame before blocking the browser in the second
      await Vue.skipFrame();
      for (let i = 1; i < 1000000000; i++) {

      }
      console.log('Calculation finish');
    }
  },

  mounted() {
    this.$on('loading-show', this.showCallback);
  },

  destroyed() {
    this.$off('loading-show', this.showCallback);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <button @click="start">Start</button>
  <h1 v-show="show">Shown</h1>
</div>