#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().
Комментарии:
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
})
}
});
Приведенный выше код может сработать для вас. Вам все еще нужно провести много тестирования и отладки. Но я бы ожидал, что все будет работать именно так.
Примечание:
-
Пример кода создает только один
Vue()
экземпляр и инициализирует прослушиватель сокета вcreated
перехватчике. Таким образом, существует только один прослушиватель / обработчик для ваших сообщений сокета. -
Обработчик сообщений сокета использует функцию стрелки 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