如何在 Vue 3 项目中显示使用 date-fns 格式的 Firestore 时间戳字段?

Posted

技术标签:

【中文标题】如何在 Vue 3 项目中显示使用 date-fns 格式的 Firestore 时间戳字段?【英文标题】:How to display a Firestore timestamp field, formatted with date-fns, in a Vue 3 project? 【发布时间】:2021-12-26 23:12:12 【问题描述】:

在 Cloud Firestore 文档中,在标题为 reviews 的集合中,我有一个标题为 createdAttimestamp 类型的字段。

我正在尝试使用 date-fns 日期实用程序库的 formatDistanceToNow 在 DOM 中显示该 createdAt 字段,它以单词形式返回给定日期与现在之间的距离,例如 " 小于一分钟前”

例如,在给定的 Firestore 文档中,createdAttimestamp 类型,其值为 11/14/2021 10:49:09 AM

我可以访问和显示createdAt 字段,如下所示:

<p> review.createdAt </p> 在 DOM 中产生这样的结果:Timestamp(seconds=1636904949, nanoseconds=271000000)

<p> review.createdAt.toDate() </p> 在 DOM 中产生以下结果:2021 年 11 月 14 日星期日 10:49:09 GMT-0500(东部标准时间)

我正在尝试按如下方式显示 date-fns 格式的日期:

<template> 部分:<p> computedDateToNow </p>

<script> 部分:

const computedDateToNow = computed(() => 
  return formatDistanceToNow(review.createdAt.toDate())
)

console.log(computedDateToNow)

我在控制台中遇到的错误是

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'toDate')
    at ReactiveEffect.eval [as fn] (ReviewDetails.vue?5986:590)
    at ReactiveEffect.run (reactivity.esm-bundler.js?a1e9:160)
    at ComputedRefImpl.get value [as value] (reactivity.esm-bundler.js?a1e9:1087)
    at unref (reactivity.esm-bundler.js?a1e9:1001)
    at Object.get (reactivity.esm-bundler.js?a1e9:1004)
    at Proxy.render (ReviewDetails.vue?5986:34)
    at renderComponentRoot (runtime-core.esm-bundler.js?5c40:756)
    at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js?5c40:4594)
    at ReactiveEffect.run (reactivity.esm-bundler.js?a1e9:160)
    at callWithErrorHandling (runtime-core.esm-bundler.js?5c40:6987)

review.createdAtreview.createdAt.toDate() 在 DOM 中的 <p> 标签之间显示得很好。

为什么toDate() 方法(link to that in Firebase docs)会导致computedDateToNow 出现问题?

更新基于this comment,“很可能这个javascript函数是在实际html加载之前放置的”我添加了一个if (review.createdAt)语句并且错误消失了,但是 review.createdAtconsole.log(computedDateToNow) 中仍未定义

这是带有 if 语句的代码块:

const computedDateToNow = computed(() => 
    if (review.createdAt) 
      console.log('begin new console dot log',review.createdAt,'end new console dot log')
      return formatDistanceToNow(review.createdAt.toDate())
    
      
    )

添加(响应@Raffobaffo 的请求):

<script>

import useDocument from '@/composables/useDocument'
import getDocument from '@/composables/getDocument'
import  computed  from 'vue'
import  formatDistanceToNow  from 'date-fns'

export default 
  props: ['id'],
  components:  ,
  setup(props) 
    const  error, document: review  = getDocument('reviews', props.id)

    const  deleteDoc, updateDoc  = useDocument('reviews', props.id)


// BEGIN formatting timestamp

console.log('begin new console dot log',review.createdAt,'end new console dot log')

    const computedDateToNow = computed(() => 
    if (review.createdAt) 
      console.log('begin new console dot log',review.createdAt,'end new console dot log')
      return formatDistanceToNow(review.createdAt.toDate())
    
      
    )

    console.log(computedDateToNow)
    
// END formatting timestamp



    return  error, review, formatDistanceToNow, computedDateToNow   
  

</script>

感谢您的帮助!

【问题讨论】:

console.log 计算属性中的 review.createdAt 并检查它是否可用。在大多数情况下,我认为您的review.createAt 日期当时不可用,可能是因为之后返回了来自firestore 的响应。 谢谢@Salvino 您建议的console.log 回来了undefined。我有些困惑,因为review.createdAt 显示在 DOM 中。 不看你的代码很难理解这一点。请发布一个最小可重现问题,以便我们检查并为您提供合适的解决方案。 嗨,您可以将您定义const computedDateToNow = computed(() =&gt; return formatDistanceToNow(review.createdAt.toDate()) )的位置的完整部分粘贴到脚本中吗?是在setup函数里面吗? 我刚刚添加了它。谢谢@Raffobaffo 【参考方案1】:

我可以建议使用npm package 经理:

在这种情况下,您可以直接在组件中使用过滤器。

// my-component.js
import  dateFilter  from "vue-date-fns";
 
export default 
    filters: 
        date: dateFilter
    


<!-- my-component.vue -->
<template>
    <div>Now:  new Date() | date </div>
</template>

如果您想继续使用当前代码,也许您可​​以尝试调试您的const computeDateToNow,看看您得到的值是什么。

根据您分享的date-fns 的文档,这里是console.log 的示例:

console.log(format(new Date(), "'Today is a' eeee"))

输出应该是:

//=> "Today is a Wednesday"

这将帮助您验证功能是否执行良好;如果没有,请验证库的导入。

建议将数据类型从 const 更改为 var。 请记住,var 可以更新和重新声明,而 const 不仅不能重新声明,也不能重新赋值。

【讨论】:

谢谢@Jose。我可能最终会尝试您建议的 vue-date-fns 包,但我的犹豫是我不明白为什么,正如我在原始问题中所述,&lt;p&gt; review.createdAt &lt;/p&gt;&lt;p&gt; review.createdAt.toDate() &lt;/p&gt; 都会导致 DOM 中的值,但是Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'toDate') date-fns 函数中不断出现错误。恕我直言,如果我只是在包裹上厚厚的包裹而不是了解实际出了什么问题,我就无法成长。再次感谢。【参考方案2】:

一个点在计算上: 只要检查通过,您就会返回一个值,而计算属性应该总是 return something。

所以我宁愿尝试这种方法:

const computedDateToNow = computed(() => 
if (review.createdAt) 
  console.log('begin new console dot log',review.createdAt,'end new console dot log')
  return formatDistanceToNow(review.createdAt.toDate())

  return 'not-available';
)

【讨论】:

谢谢@Raffobaffo。我今天晚些时候会尝试,但它似乎无法解决核心问题。

以上是关于如何在 Vue 3 项目中显示使用 date-fns 格式的 Firestore 时间戳字段?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VueJS 中使用 Date-FNS?

如何使用 date-fns 找到一周中最近的一天

如何使用 date-fns 格式化日期?

vue/cli2.0优化

获取 date-fns 中两个日期之间的持续时间,以天:小时:分钟:秒格式

如何使用 JavaScript date-fns 库在特定时区格式化日期/时间