Индикатор загрузки Vue.js для пересчета вычисляемого свойства - PullRequest
0 голосов
/ 02 июня 2018

У меня есть небольшое веб-приложение, написанное на Vue.js, и я пытаюсь показать индикатор загрузки на странице, пока список элементов фильтруется и перерисовывается.Список не выбирается асинхронно, это просто список элементов из вычисляемого свойства, основанный на некоторых полях фильтра, который обновляется по мере изменения фильтров.Перед обновлением списка в пользовательском интерфейсе происходит задержка в несколько секунд, поскольку в списке содержится около 1400 элементов, и каждый элемент представляет собой компонент карточного стиля с изображением, кнопкой, значками и некоторым текстом.Я попытался показать сообщение «Загрузка ...» между изменениями фильтра и рендерингом нового списка, но, похоже, не смог показать его пользователю.

Я собрал упрощенную скрипку в видеПример: 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, она никогда не обновляется в пользовательском интерфейсе.

У меня есть код, который, как я надеялся, будет отображать «загрузку» при вызове вычисляемого свойства и по завершении рендеринга списка., скрыть это и показать список.Почему это не работает?Почему меняется DOM, но пользовательский интерфейс никогда не обновляется?Интерфейс не обновляется, потому что все динамические элементы находятся в одном и том же компоненте, и он не сбрасывается до тех пор, пока не закончится рендеринг списка?Есть ли лучший способ добиться этого?

Спасибо!

1 Ответ

0 голосов
/ 02 июня 2018

Вы делаете длинный синхронный процесс.Эти типы процессов связывают поток пользовательского интерфейса, то есть вы не можете ничего делать на вкладке, и DOM не может обновляться в течение этого времени.

Чтобы выполнять такие длинные процессы, как вы, вы должны поместить его в Web Worker .Используя API-интерфейс Messaging, вы затем отправляете сообщение работнику с предложением составить список, и оно отправляет сообщение обратно, когда это будет сделано.Это сделало бы ваш процесс асинхронным и не связывало бы пользовательский интерфейс.

Примечание: возможно, вы захотите подумать об использовании нумерации страниц для отображения такого большого списка.Поскольку скрытие / отображение этого множества элементов также приведет к блокировке браузера.

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);

app.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});
            });
          }
        }
      });

Демонстрация по плункеру

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...