vue.js v-для списка, который не обновляется

#javascript #vue.js

#javascript #vue.js

Вопрос:

У меня есть этот список:

 <ul id="tab">
    <li v-for="list in names">
        {{ list.personName }}
    </li>
</ul>
  

И тогда у меня есть этот объект vue:

 var vm = new Vue ({
    el: '#tab',
        data: {
            names: //an object array coming from the server
        }
    });
  

Таким образом, данные «имен» обновляются и получают информацию с сервера. Однако, когда имена обновляются / изменяются, это не отражается в списке на стороне клиента. Элементы, которые появляются в списке, отражают только те элементы, которые были там при первоначальной загрузке страницы.

В vue.js инструменты разработчика в Google Chrome, я всегда могу видеть обновленные данные «имен», но это просто не отражается на самом DOM.

ПРАВКА1: Что в ‘имени’:

 names: Array[2]
    0: Object
    _id: "580aeafd017fbfb81a3a794d"
    personName: "hi"

    1: Object
   _id: "580c4455ccc9e39c21f02434"
   personName: "test"
  

ПРАВКА2

Итак, я использую node.js и передача данных в реальном времени с узла клиенту через сокет.ввод-вывод, подобный этому:

 socket.on('userDocument', function(userDocument) {
    var vm= new Vue ({
        el: '#tab',
        data: {
            names: //an object array coming from the server
        }
    });
});
  

Комментарии:

1. Можете ли вы показать код, который вы используете для настройки names в компоненте?

2. Используете ли вы jQuery для извлечения данных сервера? Или вы должны vue-resource выполнить эту работу за себя? Можете ли вы показать эту часть кода? Это помогает, потому что может возникнуть потенциальная проблема с привязкой this в обработчиках обещаний.

3. Я использую nodejs и сокет. ввод-вывод для извлечения любых изменений в данных в реальном времени и отправки их клиенту. Я знаю vue.js можете увидеть изменения, потому что я проверил в vuejs developers tools в Chrome…it это просто сам DOM, который не будет обновляться, если я не обновлю страницу.

4. Вы уверены, что проблема не в прослушивателях сокетов? Можете ли вы прочитать входящее сообщение через console.log() , прежде чем переходить к Vue? Возможно, вы захотите добавить сокет. также тег ввода-вывода . Тем не менее, я написал свой ответ ниже, ознакомьтесь с ним.

5. Да, я могу прочитать входящее сообщение через console.log . Сообщение находится в моей ПРАВКЕ1

Ответ №1:

Обнаружение изменений массива в Vue немного сложно. Большинство методов массива на месте работают так, как ожидалось (т. Е. Выполнение сращивания в вашем массиве $ data.names сработало бы), но прямое присвоение значений (т. Е. $data.names[0] = ‘Joe’) не привело бы к обновлению реактивно отображаемых компонентов. В зависимости от того, как вы обрабатываете результаты на стороне сервера, вам может потребоваться подумать об этих параметрах, описанных в документации in vue: Обнаружение изменения массива.

Некоторые идеи для изучения:

  • используя v-bind:key=»some_id», чтобы лучше
  • использование нажатия для добавления новых элементов
  • используя Vue.set(example1.items, indexOfItem, newValue) (также упоминается Artokun)

Комментарии:

1. В моем случае это странно, я создал вычисляемое свойство cUsers для свойства данных users (массива объектов), чтобы проверить его реактивность. Каждый раз, когда я обновляю эти данные users с помощью выборки, функция вычисляемого свойства cUsers вызывается, но v-for loop для одних и тех же данных users не обновляется.

Ответ №2:

Если он передается как объект с сервера, обязательно используйте Vue.set(obj, ключ, значение) при реактивной привязке к data().

http://vuejs.org/api/#Vue-set

Комментарии:

1. Для ясности, все данные в массиве могут быть на стороне клиента, и вам все равно нужно будет вызвать Vue.set , чтобы заставить v-for повторно отобразить на основе массива (в отличие от arr[idx] = newValue )

Ответ №3:

Я не эксперт по сокетам, но это не рекомендуемый способ обработки соединения с сокетами.

Сокет устанавливает постоянное соединение с сервером, и вы можете в любой момент получить данные с сервера. Ваш socket.on("message", function(data) {...}) является обработчиком для этих асинхронных данных с сервера.

В вашем примере кода ваш обработчик сообщений, похоже, создает новый экземпляр Vue() каждый раз, когда сервер отправляет некоторые данные. Вы быстро получите несколько версий Vue() экземпляров, что потенциально приведет к сбою вкладки браузера пользователя из-за перегрузки памяти.

Я не использую socket.io, но, основываясь на моем понимании веб-приложений в целом, вот как я бы предпочел это сделать:

 // Initialize your Vue app first:
new Vue ({
    el: '#tab',
    template: `
        <ul id="tab">
            <li v-for="list in names">
                {{ list.personName }}
            </li>
        </ul>
    `
    data: {
        names: [] // start with blank, and modify later
    },
    created: function() {
        // This 'created' hook is called when your Vue instance is setup
        // TODO: Initialize your socket connection here.
        // ...
        // Setup your socket listener
        mySocketInstance.on("message", response_data => {
            // Assuming your response_data contains 'user_names' array
            this.names = response_data.user_names;
            // Note: 'this' in the above line points to outer scope, that is why we need arrow functions
        })
    }
});
  

Приведенный выше код может сработать для вас. Вам все еще нужно провести много тестирования и отладки. Но я бы ожидал, что все будет работать именно так.

Примечание:

  1. Пример кода создает только один Vue() экземпляр и инициализирует прослушиватель сокета в created перехватчике. Таким образом, существует только один прослушиватель / обработчик для ваших сообщений сокета.

  2. Обработчик сообщений сокета использует функцию стрелки javascript, которая гарантирует, что ваша внешняя область this совпадает с внутренней областью this . Таким образом, вы сможете правильно обновить свой names .

Комментарии:

1. аааа, ладно. Я собираюсь отсортировать свой код и модифицировать его в соответствии с вашими рекомендациями. Спасибо за всю эту информацию.

2. Также, пожалуйста, проверьте мой другой комментарий под вопросом. Возможно, вы захотите также отладить часть сокета, используя console.log(server_response) , прежде чем переходить к Vue.

Ответ №4:

Что я обнаружил, так это то, что даже если вы всплываете, а затем возвращаете элемент обратно в список, v-for не обновит список.

Например, код this.items.pop(); обновит список, но this.items.push(this.items.pop()); не будет. Понятия не имею, почему.

В качестве решения я проделал следующий трюк (очень некрасивый, извините), и он работает:

 <Column v-if="col in columns" ....

methods: {
    refreshColumns() {
        this.columns_temp = [...this.columns];
        this.columns = [];
        this.$nextTick(() => {
            this.columns = [...this.columns_temp];
        });
    },
}
  

Я дам вам знать, если найду правильное решение. Но на данный момент у меня нет времени на это.

Ответ №5:

у меня есть решение. Используйте компонент без данных. вместо данных используйте props для отправки данных вашему компоненту 🙂 это сработает.

Ваш список:

 <ul id="tab">
    <my-li v-for="name in names" :my-name="name"></my-li>
</ul>
  

или ваш список:

 <ul id="tab">
    <my-li v-for="name in names">{{name}}</my-li>
</ul>
  

Ваш скрипт:

 let Mycomponent = Vue.component("my-li",{
   props:['my-name'],
   template:"<li>{{myName}}<slot></slot></li>"
});
var vw = new Vue({
  el:"#tab",
  data:{
    names:['ali','reza','matin','mehdi','ahora','me']  
  },
  methods:{
          changeList:function(myList,index,newVal){
              let backupList = this.names;
              backupList[index] = newVal;
              this.names = []
              this.names = backupList;
            }
  },
  component:[Mycomponent]
  })
  

вы можете изменить значение списка с помощью этого метода:

 vw.changeList(vw.names,1,"hello")
  

если вам нужно задать для списка имена, используйте это

 vw.names = [];
vw.names = YourList;
  

Это просто, чувак 🙂

результат: jsfiddle.net/khaled_developer/5n316jpo