Vue момент js обновление относительного времени в реальном времени с отметкой времени - PullRequest
2 голосов
/ 19 апреля 2020

Я создаю приложение для форума и с помощью v-for я хочу показать, когда все комментарии были опубликованы с моментом js относительного времени, проблема в том, что рендер никогда не меняется с 'Несколько секунд go». В этом вопросе ответ показывает, что я хочу достичь, в основном используя интервал при создании компонента:

  created() {
    setInterval(() => {
      this.messages = this.messages.map(m => {
        m.ago = moment(m.time).fromNow();
        return m;
      });
    }, 1000);
  }

Но из-за этого я получаю данные непосредственно из vuex, Я не понимаю, как интегрировать решение с моим кодом.

Это мой магазин. 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"])
};

Ответы [ 2 ]

2 голосов
/ 19 апреля 2020

Лучше всего абстрагировать всю эту логику c в один компонент для отображения дат, а не запускать обновления через границы кода. Сохраняйте весь код рендеринга даты как можно более минимальным, чтобы можно было легко изменить логи рендеринга даты c в любое время.

Сама дата является данными, но визуальное представление этой даты - нет. Поэтому я не буду хранить отформатированную дату в магазине 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 опора, которая позволяет мне выбрать способ отображения даты (это может быть относительное время или конкретный c формат даты, который принимает этот момент).

1 голос
/ 19 апреля 2020

Попробуйте добавить другое действие и отправлять его каждую секунду:

 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);
  },
...