#javascript #firebase #vue.js #for-loop #google-cloud-firestore
#javascript #firebase #vue.js #for-цикл #google-облако-firestore
Вопрос:
Я создаю систему заказа еды. Я создаю страницу истории заказов и пытаюсь добиться бесконечной загрузки.
Я хочу показывать следующие пять результатов каждый раз, когда нажимаю кнопку «далее».
Каждые пять результатов должны быть возвращены в порядке убывания. Имя столбца created_at
.
Проблема в том, что если я нажму кнопку next один раз, я увижу результаты с шестого по десятый.
Но если я снова нажму кнопку, я увижу результаты с шестого по десятый.
И то же самое происходит снова и снова, каждый раз, когда я нажимаю кнопку next.
Я думаю, мне нужно использовать цикл for в моем методе. Но я не мог понять, как решить эту проблему.
Я использую firebase query в своих методах.
Мой код:
<template>
<div>
<NavbarMobile />
<CartSmartphone class="mb-5" />
<b-container class="history-mobile">
<b-row class="mb-2 orders">
<span class="ml-2 orders">Your orders</span>
</b-row>
<div class="user-section d-flex " v-for="(item, index) in history" :key="index">
<div v-if="item.status == 'processing'" class="card-area">
<div class=" mb-3" v-for="(sample, index) in item.sample" :key="index">
<router-link :to="{name:'OrderSmartphone',params:{id: item.code}}">
<b-card :img-src="sample" img-alt="Card image" img-left class="mb-3">
<b-card-text class="text">
<!-- Some quick example text to build on the card and make up the bulk of the card's content. -->
<ul class="list-unstyled">
<b-row tag="li">
<span class="shop">{{ item.business }}</span>
</b-row>
<div cols="12" class="d-flex my-3">
<span class="date">{{ item.day }}/{{ item.month }}/{{ item.year}}</span>
<span class="status">{{ item.status }}</span>
</div>
<b-row class="my-3">
<span class="price">{{ item.sale }}</span>
</b-row>
</ul>
</b-card-text>
</b-card>
</router-link>
</div>
</div>
<div v-else class="card-area">
<div class="card-area mb-3" v-for="(sample, index) in item.sample" :key="index">
<b-card :img-src="sample" img-alt="Card image" img-left class="mb-3">
<b-card-text class="text">
<!-- Some quick example text to build on the card and make up the bulk of the card's content. -->
<ul class="list-unstyled">
<b-row tag="li">
<span class="shop">{{ item.business }}</span>
</b-row>
<div cols="12" class="d-flex my-3">
<span class="date">{{ item.day }}/{{ item.month }}/{{ item.year}}</span>
<span class="status">{{ item.status }}</span>
</div>
<b-row class="my-3">
<span class="price">{{ item.sale }}</span>
</b-row>
</ul>
</b-card-text>
</b-card>
</div>
</div>
<div class="arrow-area">
<div class="svg">
<svg xmlns="http://www.w3.org/2000/svg" width="5.126" height="9.313" viewBox="0 0 5.126 9.313">
<g id="download" transform="translate(-116.995 9.036) rotate(-90)">
<path id="パス_390" data-name="パス 390" d="M8.452,117.33,4.4,121.385.344,117.33a.19.19,0,0,0-.269.269l4.189,4.189a.19.19,0,0,0,.269,0L8.722,117.6a.19.19,0,0,0-.265-.274l0,0Z" transform="translate(-0.021 0)" fill="#fff" stroke="#fff" stroke-width="0.5"/>
<path id="パス_391" data-name="パス 391" d="M4.377,121.845a.19.19,0,0,1-.135-.056L.053,117.6a.19.19,0,0,1,.269-.269l4.055,4.054,4.054-4.055a.19.19,0,0,1,.274.265l0,0-4.189,4.189A.19.19,0,0,1,4.377,121.845Z" transform="translate(0 -0.001)" fill="#fff" stroke="#fff" stroke-width="0.5"/>
</g>
</svg>
</div>
</div>
</div>
</b-container>
<b-button @click.prevent="nextPage" class="next">next</b-button>
<FooterMobile />
</div>
</template>
<script>
import CartSmartphone from "@/mobile/CartSmartphone.vue";
import NavbarMobile from "@/components/NavbarMobile.vue";
import FooterMobile from "@/sections/FooterMobile.vue";
import fireApp from '@/plugins/firebase'
const firebase = require("firebase");
require("firebase/firestore");
const db = firebase.firestore();
export default {
name: 'UserSmartphone',
components: {
CartSmartphone,
NavbarMobile,
FooterMobile
},
data() {
return {
customer: this.$route.params.id,
history: [],
sample: ""
}
},
mounted() {
// const customerId = this.$route.params.id
// this.customer = customerId
const dbOrdersRef = db.collection('OrdersUser').doc(this.$route.params.id).collection('Orders').orderBy("created_at", "desc").limit(5)
dbOrdersRef.onSnapshot((querySnapshot) => {
querySnapshot.forEach((doc) => {
const historyData = doc.data()
this.history.push(historyData)
this.sample = doc.data().sample
})
})
},
methods: {
nextPage() {
fireApp.auth().onAuthStateChanged((user) => {
if (user) {
const userId = fireApp.auth().currentUser.uid;
const first = db.collection('OrdersUser').doc(userId).collection('Orders').orderBy("created_at", "desc").limit(5)
return first.onSnapshot((querySnapshot) => {
// Construct a new query starting at this document,
// get the next 5 results.
var lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
console.log("last", lastVisible);
var next = db.collection('OrdersUser').doc(userId).collection('Orders').orderBy("created_at", "desc")
.startAfter(lastVisible)
.limit(5);
next.onSnapshot((nextQuery) => {
nextQuery.forEach((doc) => {
const nextData = doc.data()
console.log(nextData)
this.history.push(nextData)
})
})
});
}
})
},
}
}
</script>
Имя коллекции OrdersUser
, и я отправляю данные в массив с именем history
.
И затем я показываю результаты в разделе шаблона, используя цикл for .
Ответ №1:
Вы не устанавливаете последний видимый документ вне своей nextPage
функции, поэтому эта функция всегда запускает запрос после 5 исходных документов, что вам нужно сделать, это:
- Добавьте переменную, которая сохраняет последний видимый документ при первом заполнении списка, как показано ниже:
const dbOrdersRef = db.collection('OrdersUser').doc(this.$route.params.id) .collection('Orders').orderBy("created_at", "desc").limit(5); dbOrdersRef.onSnapshot((querySnapshot) => { querySnapshot.forEach((doc) => { const historyData = doc.data() this.history.push(historyData) this.sample = doc.data().sample }) this.lastVisible = querySnapshot.docs[querySnapshot.docs.length-1]; })
- Используйте
lastVisible
переменную, установленную при начальной загрузке, чтобы запустить последующий запрос, например, следующим образом:nextPage() { fireApp.auth().onAuthStateChanged((user) => { if (user) { const userId = fireApp.auth().currentUser.uid; const next = db.collection('OrdersUser') .doc(userId) .collection('Orders') .orderBy("created_at", "desc") .startAfter(this.lastVisible) .limit(5); return next.onSnapshot((nextQuery) => { nextQuery.forEach((doc) => { const nextData = doc.data() console.log(nextData) this.history.push(nextData) }) this.lastVisible = nextQuery.docs[nextQuery.docs.length-1]; }) }; }) }
- Объявите
lastVisible
переменную вашейdata()
, так как это сделает ее доступной как вnextPage()
, так и вmounted()
с помощьюthis.
, например, следующим образом:data() { return { customer: this.$route.params.id, history: [], sample: "", lastVisible: "" } },
Комментарии:
1. Спасибо за помощь, но я получил сообщение об ошибке «lastVisible не определен». Я использовал ваш первый код в разделе mounted, затем я использовал второй код в разделе methods . На самом деле, что означает «var lastVisible;» в вашем первом коде?
2. по сути, это последний документ вашего начального набора, поэтому вам нужно использовать on
startAt
для последующего набора документов, вы можете проверить эту документацию для получения более подробной информации, я проверю, в чем проблема с кодом, которым я поделился, и обновлю ответ как можно скорее.3. Я отредактировал вопрос, добавив еще один шаг для его исправления, проверьте его. Также немного изменены шаги 1 и 2.