Vue momentjs 实时更新相对时间

Dum*_*tru 12 javascript momentjs vue.js vue-component vuejs2

如何momentjs为用户实时更新相对时间?

我计算过:

computed: {
  ago() {
     return moment().fromNow();
    },
}
Run Code Online (Sandbox Code Playgroud)

当我在组件中使用时:

<span class="text-muted pr-2" v-text="ago"></span>
Run Code Online (Sandbox Code Playgroud)

我得到静态文本:a few seconds ago,如何在不重新加载页面的情况下更新此文本?我想看:a minute ago,atwo minutes ago等。

我如何为用户实时执行此操作?

小智 8

我使用 Vuex 商店中的全局“代码”解决了这个问题。它开始每 30 秒加载一次。时间的描述性消息与此自动收录器进行比较,而不是与“现在”或其他任何内容的其他实现进行比较。与每个 UI 元素每秒迭代自己的日期时间标记之类的技术相比,这种技术的优点是,Vue 中的反应式元素不会随意地定期刷新自己。在我的应用程序中,一个全局“伪现在”滚动条每 30 秒迭代一次,所有提供时间描述性说明的元素都在一帧中立即刷新。这有利于性能。

来自相关 Vuex 商店的片段:

import Vue from 'vue'

const TICKER_INTERVAL = 30000; // milliseconds

let tickerPointer = null;

const data = {
  state: {
    now: new Date,
  },

  mutations: {
    refreshTicker(state) {
      state.now = new Date;
    },
  },

  actions: {
    startTicker({commit}) {
      if (tickerPointer === null) {
        tickerPointer = setInterval(() => {
          commit('refreshTicker');
        }, TICKER_INTERVAL);
      }
    },

    haltTicker({state}) {
      clearInterval(tickerPointer);
      state.now = null;
      tickerPointer = null;
    },
Run Code Online (Sandbox Code Playgroud)

“StartTicker”在加载时由我的应用程序顶部调度一次。


Bou*_*him 7

由于moment().fromNow()不是反应性的所以你不会看到任何变化,为了处理我们修复了一个应该在created钩子中初始化的旧时间属性this.oldTime = new Date();,并根据我们调用的旧时间属性来设置一个时间间隔1smoment(this.old).fromNow();来更新我们的属性ago.

// ignore the following two lines, they just disable warnings in "Run code snippet"
Vue.config.devtools = false;
Vue.config.productionTip = false;

new Vue({
  el: '#app',

  data() {
    return {
      ago: '',
      oldTime: '',
    interval:null
    }
  },
 destroyed(){
   clearInterval(this.interval)
   },
  created() {
    this.oldTime = new Date();
    this.interval=setInterval(() => {
      this.ago = moment(this.oldTime).fromNow();
    }, 1000)
  }
});
Run Code Online (Sandbox Code Playgroud)
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://rawgit.com/moment/moment/2.2.1/min/moment.min.js"></script>

<div id="app" class="container">

  <span class="text-muted pr-2" >
  {{ago}}
  </span>
</div>
Run Code Online (Sandbox Code Playgroud)

根据@Badgy 的评论:

How would you handle it for a v-for where you show it in the UI via a function? I thought about attaching it to the message object on created and update all message objects every x seconds but not sure if its the best way

为了适应这种情况,我们应该创建一个时间间隔来更新ago每条消息的属性:

// ignore the following two lines, they just disable warnings in "Run code snippet"
Vue.config.devtools = false;
Vue.config.productionTip = false;

new Vue({
  el: '#app',

  data() {
    return {

      messages: [{
          content: 'Hello !',
          time: '2019-09-10 00:08'
        },
        {
          content: 'Hello again!',
          time: '2019-09-10 00:10'
        }
      ],
  interval:null
    }
  },
  computed: {
    msgs() {
      return messages

    }
  },
       destroyed(){
   clearInterval(this.interval)
   },
  created() {

    this.interval=setInterval(() => {

      this.messages = this.messages.map(m => {
        m.ago = moment(m.time).fromNow();
        return m;
      })
    }, 1000)
  }
});
Run Code Online (Sandbox Code Playgroud)
.primary{
color:blue
}
Run Code Online (Sandbox Code Playgroud)
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://rawgit.com/moment/moment/2.2.1/min/moment.min.js"></script>

<div id="app" class="container">

  <ul>
    <li v-for="m in messages">{{m.content}} <span class="primary">{{m.ago}}</span></li>
  </ul>
</div>
Run Code Online (Sandbox Code Playgroud)