使用Interval的Knockout Ajax仅显示更改的数据

Dim*_*las 2 javascript ajax jquery knockout.js

我有这个代码:

function MyViewModel()
{
  var myviewmodel=this;
  myviewmodel.ajaxData=ko.observableArray([]);


  myviewmodel.init=function()
  {
    updateInterval(function()
    {
      myviewmodel.getData();
    },6000);
  }

  myviewmodel.getData=function()
  {
    myviewmodel.ajaxData([])
    $.get('getData.php')
    .done(function(data)
    {
      if(data.status==='ok' && data.data)
      {
        $.map(data.data,function(f)
        {
          var last_item=new AjaxItem(f);
          myviewmodel.ajaxData.push(last_item);
        })
      }
    })
  }

  function AjaxItem(data)
  {
    var item=this;
    item.id=parseInt(data.id);
    item.name=ko.observable(data.name);
    item.surname=ko.observable(data.surname);
    item.viewed=ko.observable(true);

    setTimeout(function()
    {
       item.viewed(false);
    },600);
  }
}
var vm= new MyViewModel();
ko.applyBindings(vm)
vm.init();
Run Code Online (Sandbox Code Playgroud)

我在这个HTML中查看它

<!doctype html>
<html>
<head>
........
<script src="somejs.js"></script>

<style>
.green{
 background-color:green;
}
</style>
</head>
<body>
  <table>
    <tbody data-bind="foreach:ajaxData">
      <tr data-bind="css{'green:viewed'}">
       <td data-bind="text:name"></td><td data-bind="text:surname"></td>
      </tr>
    </tbody>
  </table>
</boby>
</html>
Run Code Online (Sandbox Code Playgroud)

问题是,当我进行调用时,我必须重新填充数组ajaxData,并且当我这样做时会出现某种"眨眼",我想要的是找到任何更改的项目并仅显示它们.

有3例不同:

  1. 我存在,但名称和姓氏不同,我想更改名称和姓氏.
  2. 项目存在于Javascript中,从调用返回的数据中不存在,因此我想从ajaxData中删除
  3. 返回的数据中不存在项,因此我想在ajaxData observable数组的末尾添加.

你们的伙伴们有一个想法如何做到这一点.

注意:问题是如何进行比较.我将如何知道返回的值是否存在于已返回的数据中.

Tom*_*lak 5

您的三个要求正是Knockout Mapping Plugin将为您做的.

但在此之前,您的一般方法有几点需要解决.

首先,让我们从您的viewmodel中获取Ajax内容.如何在一个地方收集所有API调用并将它们作为函数公开?

这暴露.getData()(反过来在.get()内部使用).

var API = {
  get: function (url, params) {
    return $.get(url, params, null, "json").then(function (result) {
      if (result.status === 'ok') return result;
      console.error("Error status for " + url + ": " + result.status, result);
    }).fail(function (jqXhr, status, error) {
      console.error("Could not get " + url + ", error is: " + error);
    });
  },
  getData: function(params) {
    return this.get('getData.php', params);
  }
};
Run Code Online (Sandbox Code Playgroud)

接下来,不要调用您的viewmodels"Viewmodel".这是他们的目的,不应该是他们的名字.你似乎在这里有两种类型的东西,物品和物品清单.我不知道你的项目实际上都是,所以我坚持的名称Item,你可以选择一个更好的一个.所以让我们做两个构造函数:

function Item(data) {
  var self = this;
  self.id = parseInt(data.id);
  self.name = ko.observable(data.name);
  self.surname = ko.observable(data.surname);
  self.viewed = ko.observable(true);
  setTimeout(function () {
    self.viewed(false);
  }, 600);
}

function ItemList() {
  var self = this;
  self.data = ko.observableArray();

  self.init = function (data) {
    ko.mapping.fromJS(data, ItemList.mapping, self);
  };
  self.load = function () {
    API.getData().done(self.init);
  };
}
Run Code Online (Sandbox Code Playgroud)

注意如何API调用gets,使ItemListviewmodel更容易阅读.还要注意如何分离load,并init允许您初始化数据视图模型的你没有通过Ajax获得(localStorage的可能?).

你可以看到我们在ko.mapping.fromJS这里打电话的方式.为了将传入对象映射到正常运行的视图模型,应该像数据属性一样调用viewmodel属性.

假设您的Ajax响应如下所示:

{
  status: "ok",
  data: [
    {id: 1, name: "Doctor", surname: "Evil"},
    {id: 2, name: "Austin", surname: "Powers"}
  ]
}
Run Code Online (Sandbox Code Playgroud)

有两个属性,statusdata.

  • status 我们想忽略,它对于viewmodel的功能并不重要.
  • data包含一个对象列表,这些对象应该成为Item我们的同名可观察数组中的实例.

为此,映射插件需要指令.ItemList为方便起见,我们可以将它们打到对象上.

ItemList.mapping = {
  ignore: ["status"],
  data: {
    key: function (data) {
      return ko.unwrap(data.id);
    },
    create: function (options) {
      return new Item(options.data);
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

这告诉映射插件不要打扰status,而是用以下对象做两件事data:

  • key函数将用于确定对象的ID,因此映射插件知道何时应使用传入对象来更新现有视图模型.我们使用该id属性.
  • create函数将用于将传入的普通对象转换为Item实例.

现在每次ko.mapping.fromJS调用来自服务器的新数据时,knockout将挑选现有对象并仅更新已更改的属性,而不是重新绘制整个列表.将从屏幕中删除丢失的对象,将添加新对象.


视图保持不变:

<table>
    <tbody data-bind="foreach: data">
        <tr data-bind="css: {green: viewed}">
            <td data-bind="text: name"></td>
            <td data-bind="text: surname"></td>
        </tr>
    </tbody>
</table>
Run Code Online (Sandbox Code Playgroud)

把它们放在一起(展开并运行示例):

var API = {
  get: function (url, params) {
    return $.get(url, params, null, "json").then(function (result) {
      if (result.status === 'ok') return result;
      console.error("Error status for " + url + ": " + result.status);
    }).fail(function (jqXhr, status, error) {
      console.error("Could not get " + url + ", error is: " + error);
    });
  },
  getData: function(params) {
    return this.get('getData.php', params);
  }
};
// -------------------------------------------------------------------

function Item(data) {
  var self = this;
  self.id = parseInt(data.id);
  self.name = ko.observable(data.name);
  self.surname = ko.observable(data.surname);
  self.viewed = ko.observable(true);
  setTimeout(function () {
    self.viewed(false);
  }, 600);
}

function ItemList() {
  var self = this;
  self.data = ko.observableArray();
  
  self.init = function (data) {
    ko.mapping.fromJS(data, ItemList.mapping, self);
  };
  self.load = function () {
    API.getData().done(self.init);
  };
}
ItemList.mapping = {
  ignore: ["status"],
  data: {
    key: function (data) {
      return ko.unwrap(data.id);
    },
    create: function (options) {
      return new Item(options.data);
    }
  }
};
// -------------------------------------------------------------------

// Ajax mockup
$.mockjax({
  url: "getData.php",
  responseText: {
    status: "ok",
    data: [
      {id: 1, name: "Doctor", surname: "Evil"},
      {id: 2, name: "Austin", surname: "Powers"}
    ]
  }
});

var vm =  new ItemList();
ko.applyBindings(vm);
vm.load();
setInterval(vm.load, 6000);
Run Code Online (Sandbox Code Playgroud)
.green {
  background-color: green;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mockjax/1.6.2/jquery.mockjax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<table>
    <tbody data-bind="foreach: data">
        <tr data-bind="css: {green: viewed}">
            <td data-bind="text: name"></td>
            <td data-bind="text: surname"></td>
        </tr>
    </tbody>
</table>

<hr>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
Run Code Online (Sandbox Code Playgroud)