我如何不断更新绑定到视图中的数据的值

时间:2018-10-30 08:37:00

标签: jquery knockout.js

我要创建这样的收件箱邮件下拉列表

enter image description here

是通过JS时刻显示消息的相对时间。下面的代码片段显示了最终结果。但是此代码的问题在于,以毫秒为单位的时间不会按间隔更新,以显示毫秒与当前日期的相对时间。所以我尝试在方法内部使用设置间隔。

未设置时间间隔示例(可以正常工作,但是最终转换时间在第一次更改后不会改变)

graphql(RaceResultsQuery, {
    props: ({ ownProps, data }) => ({
        race_results: _.get(data, 'me.my_race_results', []),
    }),
}),
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://momentjs.com/downloads/moment.js"></script>

<table>
        <thead>
            <tr><th>First name</th><th>Last name</th></tr>
        </thead>
        <tbody data-bind="foreach: people">
            <!-- ko if: ($index() < 5) -->
            <tr>
                <td data-bind="text: firstName"></td>
                <td data-bind="text: message"></td>
                <td data-bind="text: $root.converttime(dateCreated)"></td>
            </tr>
            <!-- /ko -->
        </tbody>
    </table>

    
    <script type="text/javascript">
        var viewmodel = {
            people: ko.observableArray([
                { firstName: 'Bert', message: 'Bertington', dateCreated:1540887096175 },
                { firstName: 'Charles', message: 'Charlesforth',dateCreated:1540887096175 },
                { firstName: 'Author', message: 'Dentiste', dateCreated:1540887096175 }
                
            ])
        };
        viewmodel.converttime = function (milliseconds){
        
      
        
        return moment(milliseconds).fromNow();

         
        };
        ko.applyBindings(viewmodel);
        
    </script>

使用“设置间隔示例”:但结果很尴尬

<script src="https://momentjs.com/downloads/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://momentjs.com/downloads/moment.js"></script>

<table>
        <thead>
            <tr><th>First name</th><th>Last name</th></tr>
        </thead>
        <tbody data-bind="foreach: people">
            <!-- ko if: ($index() < 5) -->
            <tr>
                <td data-bind="text: firstName"></td>
                <td data-bind="text: message"></td>
                <td data-bind="text: $root.converttime(dateCreated)"></td>
            </tr>
            <!-- /ko -->
        </tbody>
    </table>

    
    <script type="text/javascript">
        var viewmodel = {
            people: ko.observableArray([
                { firstName: 'Bert', message: 'Bertington', dateCreated:1540887096175 },
                { firstName: 'Charles', message: 'Charlesforth',dateCreated:1540887096175 },
                { firstName: 'Author', message: 'Dentiste', dateCreated:1540887096175 }
                
            ])
        };
        viewmodel.converttime = function (milliseconds){
        
        return setInterval(function()
        {
        
          return moment(milliseconds).fromNow();

        }, 3000);
      
        
       

         
        };
        ko.applyBindings(viewmodel);
        
    </script>

1 个答案:

答案 0 :(得分:1)

这是我经常采用的方法:

您可以创建一个时钟类/对象,以暴露包裹在可观察对象中的moment。时钟负责每x毫秒更新此时刻。

只要您在computed中使用此刻,就会拥有一个自动更新的值!

const Clock = (freq) => {
  let active = null;
  const now = ko.observable(moment());
  const tick = () => now(moment());
  const loop = () => {
    active = setTimeout(loop, freq);
    tick();
  }
  
  return {
    now: ko.pureComputed(now), // read only
    start: loop,
    stop: () => clearInterval(active)
  }
};


function App() {
  
  const clock = Clock(1000);
  const creationTime = moment();
  const launchTime = moment().add(1, "minute");
  
  this.countDown = ko.pureComputed(
    () => launchTime.from(clock.now())
  );
  
  this.stopwatch = ko.pureComputed(
    () => clock.now().diff(creationTime, "seconds")
  );
  
  clock.start();
}

ko.applyBindings(new App());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<p>Time till launch: <code data-bind="text: countDown"></code></p>
<p>Time elapsed: <code data-bind="text: stopwatch"></code></p>

以下是您的数据示例:

const Clock = (freq) => {
  let active = null;
  const now = ko.observable(moment());
  const tick = () => now(moment());
  const loop = () => {
    active = setTimeout(loop, freq);
    tick();
  }

  return {
    now: ko.pureComputed(now), // read only
    start: loop,
    stop: () => clearInterval(active)
  }
};

const Message = (clock, msgData) => ({
  firstName: msgData.firstName,
  message: msgData.message,
  timeIndicator: ko.pureComputed(
    () => moment(msgData.dateCreated).from(clock.now())
  )
});

const App = () => {
  const clock = Clock(100);
  clock.start();

  return {
    messages: ko.observableArray(
      getMsgData()
        .map(msgData => Message(clock, msgData))
    )
  }
};

ko.applyBindings(App());

function getMsgData() {
  return [{
      firstName: 'Bert',
      message: 'Bertington',
      dateCreated: Date.now()
    },
    {
      firstName: 'Charles',
      message: 'Charlesforth',
      dateCreated: 1540889093175
    },
    {
      firstName: 'Author',
      message: 'Dentiste',
      dateCreated: 1540887096175
    }

  ]
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<h2>Messages</h2>
<ul data-bind="foreach: messages">
  <li>
    <em data-bind="text: timeIndicator"></em><br/>
    <strong data-bind="text: firstName"></strong>: <span data-bind="text: message"> </span>
  </li>
</ul>