【问题标题】:VueJS - event emitted - show HTML before other calculationsVueJS - 发出的事件 - 在其他计算之前显示 HTML
【发布时间】:2019-08-17 12:36:36
【问题描述】:

希望:

在发出事件时显示 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>

【问题讨论】:

  • 嗨 @KGabor 你应该把你的 showCallback 放在方法中:{}
  • 嗨@Birante 更新了sn-p代码,还是不行

标签: javascript vue.js


【解决方案1】:
  1. 您不应使用 for 循环进行测试,而应使用 setTimeout。否则你的 UI 将不会更新。

  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>

【讨论】:

  • 你的sn-p有几个问题:首先我认为“h1”的条件是错误的。其次,您正在更改在按钮按下时调用的原始函数中的“完成”变量(“开始”函数)而不是在事件回调中,这就是我认为更新 UI 的原因。
  • sn-p 可以工作,只是在 StackOverflow 中不行...如果你打开 sn-p 编辑器并运行它,你会看到。
  • 当然,如果我打开它,它可以工作,但仍然没有回答问题,如何解决事件发出时 UI 部分的显示。 (这是一个最小的工作示例,在实际项目中它们是独立的组件。一个正在运行计算,一个正在尝试显示加载屏幕)
  • 请考虑 setTimeOut 方法试图延迟繁重的代码执行超过 javascript 中的 vue dom 计算以及完整的浏览器渲染框架(html、css) - 因此它会产生竞争条件 - 大多数时间值得注意在移动设备上。但是有一些方法:Vue-&gt;nextTickWindow-&gt;requestAnimationFrame 可以防止这种情况,而无需猜测所需的延迟;)
  • @Estradiaz 设置的超时正在替换代码以模拟工作。它应该会造成延迟,而且效率不高。
【解决方案2】:

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>

【讨论】:

  • 这个可行,但没有办法用某些东西(例如,用 await 函数调用)替换 requestAnimationFrame 调用,所以我不需要将 nextTick 之后的所有内容包装到 lambdas 中?跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-31
  • 2020-09-16
  • 1970-01-01
  • 2020-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多