【问题标题】:Vue momentjs update relative time in real timeVue momentjs 实时更新相对时间
【发布时间】:2019-06-14 06:27:58
【问题描述】:

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

我已经计算过了:

computed: {
  ago() {
     return moment().fromNow();
    },
}

当我在组件中使用这个时:

<span class="text-muted pr-2" v-text="ago"></span>

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

我怎样才能为用户实时做到这一点?

【问题讨论】:

    标签: javascript vue.js vuejs2 vue-component momentjs


    【解决方案1】:

    由于moment().fromNow() 不是响应式的,因此您不会看到任何更改,因此我们修复了一个旧时间属性,该属性应在created 钩子中初始化this.oldTime = new Date();,并且设置一个1s的时间间隔,基于我们调用moment(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)
      }
    });
    <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>

    基于@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)
      }
    });
    .primary{
    color:blue
    }
    <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>

    【讨论】:

    • 您将如何处理 v-for 通过函数在 UI 中显示它?我想在创建时将其附加到消息对象并每 x 秒更新一次所有消息对象,但不确定它是否是最好的方法
    • 我无法理解您的用例,您能否发布一个完整的问题并清楚地解释它
    • 不需要单独的帖子,它非常简单:假设您从使用 Momentjs 显示时间戳的服务器获取聊天,现在用于呈现您的方法不适合的消息列表我想问你有什么想法
    • 谢谢,我认为如果您将对象消息传递给子组件,您需要使用 Vue.set 而不是分配它,因为它会出现反应性问题(在我的情况下必须这样做)只是如果有人偶然发现它
    • 不是也要把destroyed()钩子里的区间删掉吗?
    【解决方案2】:

    我在我的 Vuex 商店中使用全局“代码”解决了这个问题。它每 30 秒开始在负载上增加自己。时间的描述性消息与此代码而不是“现在”或其他任何实现进行比较。与每个 UI 元素每秒迭代其自己的日期时间代码这样的技术相比,这种技术的优势在于,您在 Vue 中没有所有的响应式元素都定期刷新自己,这一切都是自愿的。在我的应用程序中,一个全局“伪现在”代码每 30 秒迭代一次,并且所有提供时间描述性说明的元素都在一帧中一次刷新。这有利于提高性能。

    来自相关 Vuex 商店的 sn-p:

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

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

    【讨论】:

    • 喜欢这个解决方案:)。
    猜你喜欢
    • 2020-08-01
    • 2015-07-15
    • 2016-11-16
    • 2013-08-03
    • 2020-03-29
    • 2015-05-01
    • 1970-01-01
    • 2017-11-02
    • 2019-05-20
    相关资源
    最近更新 更多