Vue,firestore:合并集合后如何显示 LIVE 数据
Posted
技术标签:
【中文标题】Vue,firestore:合并集合后如何显示 LIVE 数据【英文标题】:Vue, firestore: how to display LIVE data after merging collections 【发布时间】:2021-01-04 18:22:41 【问题描述】:见下方编辑
与my last question 相比,我有了很大的进步,但经过几天的工作,我再次陷入困境。
将 Vue、Vue-router、Vuex 和 Vuetify 与 Google 上的数据一起使用可以 Firestore
我想实时更新我的数据,但我找不到执行此操作的方法。 我是否需要重组,例如将产品和类别转移到一个集合中? 或者是否有任何绑定或查询魔法来完成这项工作。 正如您在下面看到的,它可以很好地加载点击数据,但我需要实时绑定,因为您可以打开页面并且有人可以出售最后一块(amountLeft = 0)。 (还有很多未来的想法)。
我的数据结构如下:
categories:
cat_food:
name: 'Food'
parentCat: 'nC'
,
cat_drinks:
name: 'Food'
parentCat: 'nC'
,
cat_beer:
name: 'Beer'
parentCat: 'cat_drinks'
,
cat_spritz:
name: 'Spritzer'
parentCat: 'cat_drinks'
,
products:
prod_mara:
name: 'Maracuja Spritzer'
price: 1.5
amountLeft: 9
cat: ['cat_spritz']
,
prod_capp:
name: 'Cappuccino'
price: 2
cat: ['cat_drinks']
,
类别和产品构成一棵树。 GIF 显示我打开类别以显示产品。当您有价格标签时,您会看到它是一种产品。 您可以看到有两个类别具有相同的父项 (cat_drinks)。 产品 prod_capp 也被分配到类别并与类别并排显示。
我目前是这样获取数据的:
catsOrProd.js
import catsColl, productsColl from '../firebase'
const state =
catOrProducts: [],
const mutations =
setCats(state, val)
state.catOrProducts = val
const actions =
// https://vuefire.vuejs.org/api/vuexfire.html#firestoreaction
async bindCatsWithProducts( commit, dispatch , CatID)
if (CatID)
// console.log('if CatID: ', CatID)
await Promise.all([
catsColl.where('parentCat', '==', CatID).orderBy('name', 'asc').get(),
productsColl.where('cats', 'array-contains', CatID).orderBy('name', 'asc').get()
])
.then(snap => dispatch('moveCatToArray', snap))
else
// console.log('else CatID: ', CatID)
await Promise.all([
catsColl.where('parentCat', '==', 'nC').orderBy('name', 'asc').get(),
productsColl.where('cats', 'array-contains', 'nC').orderBy('name', 'asc').get()
])
.then(snap => dispatch('moveCatToArray', snap))
,
async moveCatToArray( commit , snap)
const catsArray = []
// console.log(snap)
await Promise.all([
snap[0].forEach(cat =>
catsArray.push( id: cat.id, ...cat.data() )
),
snap[1].forEach(cat =>
catsArray.push( id: cat.id, ...cat.data() )
)
])
.then(() => commit('setCats', catsArray))
export default
namespaced: true,
state,
actions,
mutations,
这是我的 vue 文件的一部分,它在屏幕上显示数据。我省略了不必要的部分。 要打开所有带有道具的路线,然后单击类别将路由器发送到下一个类别。 (这样我可以使用浏览器功能向后移动)。 Sale.vue
<template>
...........
<v-col
v-for="catOrProduct in catOrProducts"
:key="catOrProduct.id"
@click.prevent="leftClickProd($event, catOrProduct)"
@contextmenu.prevent="rightClickProd($event, catOrProduct)">
....ViewMagic....
</v-col>
............
</template>
<script>
.........
props:
catIdFromUrl:
type: String,
default: undefined
,
computed:
// https://***.com/questions/40322404/vuejs-how-can-i-use-computed-property-with-v-for
...mapState('catOrProducts', ['catOrProducts']),
,
watch:
'$route.path'() this.bindCatsWithProducts(this.catIdFromUrl) ,
,
mounted()
this.bindCatsWithProducts(this.catIdFromUrl)
,
methods:
leftClickProd(event, catOrProd)
event.preventDefault()
if (typeof (catOrProd.parentCat) === 'string') // when parentCat exists we have a Category entry
this.$router.push( name: 'sale', params: catIdFromUrl: catOrProd.id )
// this.bindCatsWithProducts(catOrProd.id)
else
// ToDo: Replace with buying-routine
this.$refs.ProductMenu.open(catOrProd, event.clientX, event.clientY)
,
</script>
编辑 24.09.2020
我已将绑定逻辑更改为
const mutations =
setCatProd(state, val)
state.catOrProducts = val
,
const actions =
async bindCatsWithProducts( commit, dispatch , CatID)
const contain = CatID || 'nC'
const arr = []
catsColl.where('parentCat', '==', contain).orderBy('name', 'asc')
.onSnapshot(snap =>
snap.forEach(cat =>
arr.push( id: cat.id, ...cat.data() )
)
)
productsColl.where('cats', 'array-contains', contain).orderBy('name', 'asc')
.onSnapshot(snap =>
snap.forEach(prod =>
arr.push( id: prod.id, ...prod.data() )
)
)
commit('setCatProd', arr)
,
这很有效,因为当我在后端更改某些内容时数据会更新。
但是现在每次发生变化时我都会添加一个对象。例如,我改变了价格。现在我明白了:
我不知道为什么,因为我在 Vue 中设置了 key
字段。渲染代码为:
<v-container fluid>
<v-row
align="center"
justify="center"
>
<v-col
v-for="catOrProduct in catOrProducts"
:key="catOrProduct.id"
@click.prevent="leftClickProd($event, catOrProduct)"
@contextmenu.prevent="rightClickProd($event, catOrProduct)"
>
<div>
<TileCat
v-if="typeof(catOrProduct.parentCat) == 'string'"
:src="catOrProduct.pictureURL"
:name="catOrProduct.name"
/>
<TileProduct
v-if="catOrProduct.isSold"
:name="catOrProduct.name"
... other props...
/>
</div>
</v-col>
</v-row>
</v-container>
为什么没有正确更新?
【问题讨论】:
那么您的实际问题又是什么? 我是否理解正确,您总是希望拥有最新数量的可用产品? 目前,您的代码非常重要,请查看以下文档:firebase.google.com/docs/firestore/query-data/listen 这允许您评估更改(在 Firestore 中),然后重新设置您的商店数据。 @Tallboy:如何获取实时更新。 是的,这可能是最简单的解决方案。您不太可能只从.get()
更改为.onSnapshot
- 但我认为您可以处理一些行更改。 :)
【参考方案1】:
来自 Vuefire docs,这是您仅使用 Firebase 订阅更改的方式:
// get Firestore database instance
import firebase from 'firebase/app'
import 'firebase/firestore'
const db = firebase.initializeApp( projectId: 'MY PROJECT ID' ).firestore()
new Vue(
// setup the reactive todos property
data: () => ( todos: [] ),
created()
// unsubscribe can be called to stop listening for changes
const unsubscribe = db.collection('todos').onSnapshot(ref =>
ref.docChanges().forEach(change =>
const newIndex, oldIndex, doc, type = change
if (type === 'added')
this.todos.splice(newIndex, 0, doc.data())
// if we want to handle references we would do it here
else if (type === 'modified')
// remove the old one first
this.todos.splice(oldIndex, 1)
// if we want to handle references we would have to unsubscribe
// from old references' listeners and subscribe to the new ones
this.todos.splice(newIndex, 0, doc.data())
else if (type === 'removed')
this.todos.splice(oldIndex, 1)
// if we want to handle references we need to unsubscribe
// from old references
)
, onErrorHandler)
,
)
我通常会避免任何不必要的依赖,但根据您的目标,您可以使用 Vuefire 添加另一层抽象,或者如您所说,做一些“魔术绑定”。
import firebase from 'firebase/app'
import 'firebase/firestore'
const db = firebase.initializeApp( projectId: 'MY PROJECT ID' ).firestore()
new Vue(
// setup the reactive todos property
data: () => ( todos: [] ),
firestore:
todos: db.collection('todos'),
,
)
【讨论】:
这只会订阅 one 集合。我的问题是两个集合同时在一个数组中。当我调用 prodColl.get() 和 catchall.get() 时,您可以在问题中清楚地看到这一点 是的,很抱歉,您绝对是对的。在我编辑我的问题之前,我想指出,当您显示数组的每个元素时v-for="catOrProduct in catOrProducts"
,即使绑定正常工作,Vue won't display 也是一个反应数组。您必须设置watcher
或执行$forceUpdate()
以确保您的数据是最新的。在修复此问题之前,不要依赖屏幕上显示的内容。依靠您的DevTools extension 来查看实时更新。以上是关于Vue,firestore:合并集合后如何显示 LIVE 数据的主要内容,如果未能解决你的问题,请参考以下文章
Vue Firestore 查询。 Firestore更新数据时如何避免重复?
如何从 firestore 两个集合中获取数据并将所有数据合并在一起
如何在 Vue 3 项目中显示使用 date-fns 格式的 Firestore 时间戳字段?
Vue:检索 Firestore 数据以显示用户的企业名称 v-for 循环