#vue.js #vuejs3
Вопрос:
У меня есть приложение, которое, помимо прочего, отслеживает элементы в списках. Следующий пример, небольшое расширение примера документов (использование props
), работает правильно.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue List Component Test</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="app"></div>
<script src="./app.js"></script>
</body>
</html>
app.js (с реквизитом)
const MyApp = {
data() {
return {
items: []
}
},
template: `<list-count></list-count><list :itemList="items"></list>`,
methods: {
addItem(i) {
this.items.push(i)
}
},
provide() {
return {
listLength: Vue.computed(() => this.items.length)
}
},
}
const app = Vue.createApp(MyApp)
const ItemListCount = {
inject: ["listLength"],
template: `<p> {{ this.listLength }}</p>`
}
const ItemList = {
props: ["itemList"],
template:`<ul>
<list-item v-for="(item, index) in itemList" :i="item" :idx="index"></list-item>
</ul>`
}
const ItemListItem = {
props: ["i", "idx"],
template: `<li>{{ idx }}, {{ i.message }}</li>`
}
app.component("list", ItemList)
app.component("list-item", ItemListItem)
app.component("list-count", ItemListCount)
const vm = app.mount('#app')
Поскольку списки элементов находятся в компонентах, которые подлежат маршрутизации, я бы предпочел использовать Provide/Inject вместо того, чтобы выяснять, как передавать реквизиты по цепочке и через маршрутизатор. Следующее app.js
, которое использует provide/inject вместо реквизитов для списка, не работает.
app.js (с предоставлением/введением) … обратите внимание на удаление :itemList
привязки, добавление itemList
in provide()
и изменение ItemList
компонента для использования inject
вместо props
.
const MyApp = {
data() {
return {
items: []
}
},
template: `<list-count></list-count><list></list>`,
methods: {
addItem(i) {
this.items.push(i)
}
},
provide() {
return {
listLength: Vue.computed(() => this.items.length),
itemList: Vue.computed(() => this.items)
}
},
}
const app = Vue.createApp(MyApp)
const ItemListCount = {
inject: ["listLength"],
template: `<p> {{ this.listLength }}</p>`
}
const ItemList = {
inject: ["itemList"],
template:`<ul>
<list-item v-for="(item, index) in itemList" :i="item" :idx="index"></list-item>
</ul>`
}
const ItemListItem = {
props: ["i", "idx"],
template: `<li>{{ idx }}, {{ i.message }}</li>`
}
app.component("list", ItemList)
app.component("list-item", ItemListItem)
app.component("list-count", ItemListCount)
const vm = app.mount('#app')
Вышесказанное вызывает следующую ошибку в консоли:
Ошибка неперехваченного типа: i не определен
Я предполагаю, что ошибка заключается в том, что v-for
цикл неправильно работает с a, в то inject: ["itemList"]
время как с a он, похоже, работает нормально props: ["itemList"]
. Я не могу найти никаких соответствующих документов, которые могли бы объяснить, почему это так. Как исправить версию provider/inject?
Ответ №1:
Похоже, у вас есть какие-то ненужные вещи внутри вашей функции предоставления.
Это должно выполнить свою работу:
provide() {
return {
itemList: this.items
};
}
Смотрите этот пример рабочего кода
Обновить
Кроме того, я предполагаю, что вы используете этот код в качестве примера какой-то более сложной операции, которая фактически оправдывает использование provide/inject. В противном случае это излишество для компонента списка, и вы должны упростить его следующим образом
const MyApp = {
data() {
return {
items: []
};
},
template: `
<button @click="addItem(Math.floor(Math.random() * 100))">Add Item</button>
<list :items="items"></list>`,
methods: {
addItem(i) {
this.items.push(i);
}
}
};
const app = Vue.createApp(MyApp);
const ItemList = {
props: { items: Array },
template: `
<p>{{ items.length }}</p>
<ul>
<li v-for="(item, index) in items">{{ index ', ' item }}</li>
</ul>`
};
app.component("list", ItemList);
app.mount("#app");
Комментарии:
1. Реальное приложение включает в себя маршрутизацию, поэтому
ItemList
это один из нескольких компонентов, которые могут появиться в главном окне содержимого. Мне легче думать о том , как бы я предоставлял/вводил, а не передавал свойства<router-view></router-view>
, я думаю.