【问题标题】:How to convert data between model and view in Knockout.js?如何在 Knockout.js 中的模型和视图之间转换数据?
【发布时间】:2016-05-20 22:53:36
【问题描述】:

我接手了一个严重依赖 knockout.js 数据绑定技术的项目。该应用程序的目的基本上是显示(运动)课程。需要的是课程的名称和开始的日期(和时间)。 数据通过ajax拉取,然后通过knockout.js绑定到视图

基本上,有一个模型看起来像这样:

BaseModel: function() {
    var self = this;

    var mappingOptions = {};
    self.setMappingOptions = function (options) {
        $.extend(mappingOptions, options);
    };
    self.map = function (data) {
        ko.mapping.fromJS(data, mappingOptions, self);
        return self;
    };

    self.isNew = function() {
        return !(typeof(self.id) == 'function' && self.id() != null);
    };
}

Course: function() {
    BaseModel.call(this);
    var self = this;

    ko.mapping.fromJS({
        name: null,
        date: moment().tz('UTC').minute(0).second(0).format('YYYY-MM-DDTHH:mm:ssZ'),
        timezone: null,
        duration: null
    }, {}, self);

    self.duration = ko.integerObservable();
    self.dateDateTime = new IMWeb.ko.DateTime(self.date);
    self.timezone = self.dateDateTime.timezone();
    self.dateDateTime.timezone.subscribe(function(timezone) {
        self.timezone = timezone;
    });
}

视图像这样绑定这个模型:

<input type="text" class="form-control" id="nameInput" data-bind="value: name"/>
<input type="text" class="form-control" id="dateInput" data-bind="value: clientDateDateTime.date, event:{focus: $parent.onDateInput, mouseover: $parent.onDateInput}, enable: changeable"/>
<input id="timeInput" type="text" class="form-control" data-bind="value: dateDateTime.time, event:{focus: $parent.onTimeInput, mouseover: $parent.onTimeInput}, enable: changeable">

从服务器发送的 json 数据中的日期设置为 UTC,因此我创建了以下函数以将其转换为客户端的时区:

/**
 * Converts the given UTC date to local date of the client by subtracting
 * the local timezone offset from the given date.
 *
 * @param {Date} utcDate The date object to convert
 * @returns {Date} The converted date object
 */
var UTC2LocalDate = function (utcDate) {
    var timestamp = utcDate.getTime();              // Number of miliseconds since Jan 1st 1970, 0:00:00 UTC
    var offset = (new Date()).getTimezoneOffset();  // Local client offset in minutes
    timestamp -= offset * 60 * 1000;                // Fix date with offset by converting offset minutes to miliseconds
    return new Date(timestamp);
};

现在,棘手的部分是:如何在不过多干扰数据绑定机制的情况下运行此“转换代码”?

基本上,我希望这种行为发生:

  • 模型更改 -> 使用 UTC2LocalDate() 将模型中的日期转换为客户的本地时区并更新视图(更改模型的原始 UTC 值)。

    李>
  • 用户更改 &lt;input&gt; 中的值 -> 日期/时间转换为 UTC 并保存到模型。

【问题讨论】:

    标签: javascript knockout.js data-binding


    【解决方案1】:

    来回转换最好由writable computed 处理。对于 UTC 日期,您将拥有一个普通的 observable,并基于它计算出一个 writable。基本结构如下所示:

    vm.utcDate = ko.observable();
    vm.localDate = ko.computed({
      deferEvaluation: true,
      read: function () {
        return toLocalDate(vm.utcDate());
      },
      write: function (newLocalDate) {
        vm.utcDate(toUtcDate(newLocalDate));
      }
    });
    

    (我显然将toLocalDatetoUtcDate 的实现留给您。)在您想要显示和/或接受本地日期的任何绑定中使用localDate 变量。更新utcDate时会自动更改,输入新的localDate值时会自动更改utcDate

    【讨论】:

      【解决方案2】:

      我的方法是使用您的 UTC2LocalDate 转换 self.date 的值,然后再用于构建 dateDateTime。此时,您的用户将与本地日期时间进行交互。

      接下来你可以编写一个函数来转换回来,我们称之为 Local2UtcDate,并通过订阅 self.dateDateTime 来更新你的 self.date 值。它看起来像这样:

      self.duration = ko.integerObservable();
      self.dateDateTime = new IMWeb.ko.DateTime(UTC2LocalDate(self.date));
      self.timezone = self.dateDateTime.timezone();
      self.dateDateTime.timezone.subscribe(function(timezone) {
          self.timezone = timezone;
      });
      self.dateDateTime.subscribe(function(changedLocalDate){
          self.date(Local2UtcDate(changedLocalDate));
      });
      

      我不确定服务器期望回传的确切时间,但这样 self.dateDateTime 将是本地时间,而 self.date 将是更新的 UTC 时间。

      【讨论】:

        猜你喜欢
        • 2014-01-31
        • 2014-01-03
        • 1970-01-01
        • 1970-01-01
        • 2013-05-27
        • 1970-01-01
        • 1970-01-01
        • 2012-12-11
        • 1970-01-01
        相关资源
        最近更新 更多