javascript - 用于计算属性重新渲染的 Vue.js 加载指示器

标签 javascript vue.js vuejs2

我有一个用 Vue.js 编写的小型 Web 应用程序,我试图在过滤和重新呈现项目列表时在页面上显示加载指示器。该列表不是异步获取的,它只是一个来自计算属性的项目列表,基于一些过滤器字段,并随着过滤器的更改而更新。在 UI 中更新列表之前有几秒钟的延迟,因为列表有大约 1400 个项目,每个项目都是一个带有图像、按钮、图标和一些文本的卡片式组件。我试图在过滤器更改和新列表呈现之间显示“正在加载...”消息,但似乎无法将其显示给用户。

我整理了一个简化的 fiddle 作为例子:https://jsfiddle.net/zm4z9657/1/

编辑:这是代码片段:

new Vue({
  el: '#app',
  data: {
    even: false,
    loading: false
  },
  computed: {
    numbers: function() {
    	this.rerender();
      return this.even ? _.range(0,100000,2) : _.range(0,100000);
    }
  },
  methods: {
    rerender: function() {
      var self = this;
      
      /* self.loading = true */;
      //this.$nextTick(() => {
      	self.loading = true;
        console.log('re-render start')
        
        this.$nextTick(() => {
          self.loading = false;
          console.log('re-render end')
        })
      //})
    },
  }
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/lodash"></script>

<div id="app">
  <input type="checkbox" value="1" v-model="even" /> even?
  <div v-if="loading" id="loading">
    Loading...
  </div>
  <div v-else id="loaded">
    <div>
      <div v-for="number in numbers" :key="number">{{number}}</div>
    </div>
  </div>

</div>

该示例显示了一个数字列表 1-100000,当您单击“偶数?”时复选框过滤器,它会导致列表只更新偶数。 100000 用于显示新列表呈现中的轻微延迟。如果您检查 DOM,您可以看到在选中/取消选中该复选框后,<div id="loading">弹出 DOM 一小段时间,然后切换到 <div id="loaded"> 中的新列表.虽然加载<div>显示在 DOM 中,它永远不会在 UI 中更新。

我有一些代码,希望在调用计算属性时显示“正在加载”,并在列表完成渲染后隐藏它并显示列表。为什么这不起作用?为什么 DOM 会改变,但 UI 永远不会更新? UI 是否没有更新,因为所有动态元素都在同一个组件中,并且在列表完成呈现之前不会刷新?有没有更好的方法来实现这一点?

谢谢!

最佳答案

你正在做一个很长的同步过程。这些类型的进程占用了 UI 线程,即您不能在选项卡内执行任何操作,也不能在此期间更新 DOM。

要像您一样执行较长的流程,您应该将其放入 Web Worker 中.使用 Messaging api,您可以向 worker 发送一条消息,告诉它制作列表,它会在完成后发回一条消息。这将使您的流程异步并且不会占用 UI。

旁注:您可能想考虑使用分页来显示如此大的列表。由于隐藏/显示那么多元素也会导致浏览器锁定。

html

<input type="checkbox" value="1" v-model="even" @change="onEvenChanged" /> even?

worker.js

importScripts("lodash.js");

self.addEventListener('message', function(e) {
  var data = e.data;
  if(data.command == "start"){
    let list = data.even ? _.range(0,100000,2) : _.range(0,100000);
    self.postMessage({"list":list});
  }
}, false);

应用程序.js

var app,msgBus;
var worker = new Worker('worker.js');

//listen for messages coming back from the worker
worker.addEventListener('message', function(e) {
  var data = e.data;
  if(data.list){
    //emit a message to your vue app that the list
    //was made
    msgBus.$emit('listGenerated',data.list);
  }
}, false);

//separate empty vue for events
msgBus = new Vue();

app = new Vue({
        el: '#app',
        mounted:function(){
          //Listen for a listGenerated event
          //set numbers to the passed list
          msgBus.$on("listGenerated",(list)=>{
            this.numbers = list;
            this.loading = false;
          });
        },
        methods:{
          onEvenChanged:function(){
            this.loading = true;
            //send the start command to the worker
            //passing also the even property
            this.$nextTick(()=>{
              worker.postMessage({command:"start",even:this.even});
            });
          }
        }
      });

Demo on plunker

关于javascript - 用于计算属性重新渲染的 Vue.js 加载指示器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50651601/

相关文章:

javascript - 如何从数组数据制作嵌套有序列表

javascript - javascript 与 html5 中的表单验证

vue.js - Vue 3-Vuetify 3 : color--text not working

vue.js - 为什么 Vuejs 在观看 momentjs 时无法拾取更改?

javascript - 将组件注册到现有的 Vue.js 实例

javascript - 无法使用静态数据在 react 应用程序中执行动态搜索

javascript - JSON 到表格格式并填充空白

vue.js - 在 Vue.js 中,如何在单独的文件中编写自定义过滤器并通过在 main.js 中声明在各种组件中使用它们?

javascript - 在.vue组件中组合多个数据

vue.js - 在 Vuejs 中,如何在默认路由器 View 之外呈现组件