Vue momentjs 从时间戳实时更新相对时间
Posted
技术标签:
【中文标题】Vue momentjs 从时间戳实时更新相对时间【英文标题】:Vue momentjs update relative time in real time from timestamp 【发布时间】:2020-08-01 10:59:42 【问题描述】:我正在构建一个论坛应用程序并使用 v-for,我想显示所有 cmets 何时以 momentjs 相对时间发布,问题是渲染永远不会从“几秒钟前”改变。 在这个question中,响应显示实现了我想要的,基本上在组件创建时使用了一个区间:
created()
setInterval(() =>
this.messages = this.messages.map(m =>
m.ago = moment(m.time).fromNow();
return m;
);
, 1000);
但由于我直接从 vuex 获取数据,我不知道如何将解决方案与我的代码集成。
这是我的 store.js:
export default new Vuex.Store(
state:
comments: [],
,
mutations:
loadComments: (state, comments) =>
state.comments = comments;
,
,
actions:
loadComments: async (context) =>
let snapshot = await db
.collection("comments")
.orderBy("timestamp")
.get();
const comments = [];
snapshot.forEach((doc) =>
let appData = doc.data();
appData.id = doc.id;
appData.timestamp = moment()
.startOf(doc.data().timestamp)
.fromNow();
comments.push(appData);
);
context.commit("loadComments", comments);
,
,
);
这是我的脚本:
import db, fb from "../firebase";
import mapState from "vuex";
export default
name: "Forum",
data()
return
commentText: null,
;
,
mounted()
this.getComment();
,
methods:
getComment()
this.$store.dispatch("loadComments");
,
async sendComment()
await db
.collection("comments")
.add(
content: this.commentText,
author: this.name,
timestamp: Date.now()
);
this.commentText = null;
this.getComment();
,
created()
let user = fb.auth().currentUser;
this.name = user.displayName;
,
computed: mapState(["comments"])
;
【问题讨论】:
你能提供一个运行代码,就像我在这个answer中一样 @BoussadjraBrahim,我可以做到......但无论如何都不会工作,因为我从 firebase 带来了数据。但是,我可以用硬编码数据填充状态中的 cmets 数组,但我认为会错过问题点。 【参考方案1】:最好将所有这些逻辑抽象到一个单独的组件中来显示日期,而不是需要跨代码边界触发更新。尽量减少所有日期呈现代码,以便随时更改日期呈现逻辑。
日期本身就是数据,但该日期的可视化表示不是。所以我不会将格式化的日期存储在 Vuex 商店中。
创建一个组件<from-now>
,它以date
作为道具,并使用时刻的fromNow
呈现日期。它还负责定期(每分钟)更新自身。由于它是一个组件,因此您可以将完整日期显示为工具提示,以便用户在鼠标悬停时知道确切的时间。
const components = new Set();
// Force update every component at the same time periodically
setInterval(() =>
for (const comp of components)
comp.$forceUpdate();
, 60 * 1000);
Vue.component('FromNow',
template: '<span :title="title"> text </span>',
props: ['date'],
created()
components.add(this);
,
destroyed()
components.remove(this);
,
computed:
text()
return moment(this.date).fromNow();
,
title()
return moment(this.date).format('dddd, MMMM Do YYYY, h:mm:ss a');
,
,
);
new Vue(
el: '#app',
data:
// Test various seconds ago from now
dates: [5, 60, 60 * 5, 60 * 60].map(sec => moment().subtract(sec, 'seconds')),
,
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<div id="app">
<p v-for="date of dates">
<from-now :date="date"></from-now>
</p>
</div>
为简单起见,<from-now>
仅显示相对日期。我使用与此类似的组件,但更通用。它需要一个format
属性,它允许我选择我希望日期的显示方式(可以是相对时间,也可以是时刻接受的特定日期格式)。
【讨论】:
这是一个非常好的解决方案,但问题仍然存在......我不知道如何与我当前的代码集成,我怎样才能将我从 firebase 获得的时间戳作为道具传递给那个组件? 我不明白为什么它不起作用。在您的代码中,您正在执行moment(m.time)
,这意味着m.time
是与javascript 兼容的日期字符串或时间戳。我的组件做同样的事情。只需将您从 firebase 获得的未格式化的原始日期传递给组件上的 date
属性即可。
现在可以了,我传递的是格式化日期而不是原始数据,非常感谢。
工具提示是一个很棒的额外 XD,再次感谢您。【参考方案2】:
尝试添加另一个动作并每秒调度一次:
mutations:
loadComments: (state, comments) =>
state.comments = comments;
,
update:(state)=>
state.comments=state.comments.map(comment=>
comment.ago= moment()
.startOf(comment.timestamp)
.fromNow();
return comment;
);
,
actions:
updateComments(context)
context.commit('update')
,
loadComments: async (context) =>
....
和
created()
let user = fb.auth().currentUser;
this.name = user.displayName;
setInterval(() =>
this.$store.dispatch("updateComments");
, 1000);
,
【讨论】:
我尝试了您的解决方案,但出现此错误Uncaught ReferenceError: comments is not defined
,这是error 的图像
对不起,我在comments
之前错过了state
,它应该是state.comments=state.comments.map(comment=>
控制台没有错误了,但是还是不行……vue开发者工具中的vuex标签显示update
突变的payload为未定义。以上是关于Vue momentjs 从时间戳实时更新相对时间的主要内容,如果未能解决你的问题,请参考以下文章