3

Backbone.js/Underscore.js用来呈现一个HTML表格,当您在文本框中键入时过滤该表格。在这种情况下,它是一个基本的电话簿。
该表的内容来自一个由 JSON 文件填充的集合。JSON文件的基本示例如下:

[{
    "Name":"Sales and Services",
    "Department":"Small Business",
    "Extension":"45446",
},
{
    "Name":"Technical Support",
    "Department":"Small Business",
    "Extension":"18800",
},
{
    "Name":"Research and Development",
    "Department":"Mid Market",
    "Extension":"75752",
}]

我将文本框的值转换为小写,然后将它的值与 Collection 一起传递给这个函数,然后我将返回的值分配给一个新的 Collection 并使用它来重新呈现页面。

filterTable = function(collection, filterValue) {
    var filteredCollection;
    if (filterValue === "") {
        return collection.toJSON();
    }
    return filteredCollection = collection.filter(function(data) {
        return _.some(_.values(data.toJSON()), function(value) {
            value = (!isNaN(value) ? value.toString() : value.toLowerCase());
            return value.indexOf(filterValue) >= 0;
        });
    });
};

问题是函数是字面的。要从我的示例中找到“销售和服务”部门,我必须准确输入,或者可能只是“销售”或“服务”。我无法输入“sal serv”,但仍然找到它,这是我想要做的。

我已经编写了一些 javascript,这些 javascript 在将文本划分为单词数组时似乎非常可靠(现在已更新为使用中的代码)。

toWords = function(text) {
    text = text.toLowerCase();
    text = text.replace(/[^A-Za-z_0-9@.]/g, ' ');
    text = text.replace(/[\s]+/g, ' ').replace(/\s\s*$/, '');
    text = text.split(new RegExp("\\s+"));
    var newsplit = [];
    for (var index in text) {
        if (text[index]) {
            newsplit.push(text[index]);
        };
    };
    text = newsplit;
    return text;
};

我想遍历“拆分”数组中的每个单词并检查每个单词是否存在于其中一个键/值中。只要所有单词都存在,它就会通过真值迭代器并被添加到集合中并呈现在表中。

因此,在我的示例中,如果我键入“sal serv”,它会发现这两个字符串都存在于第一项的名称中,并且会被返回。
但是,如果我键入“sales business”,则不会返回,因为尽管这两个值都出现在该项目中,但名称部分中不存在相同的两个单词。

我只是不确定如何在 Backbone/Underscore 中编写它,或者即使这是最好的方法。我查看了文档,不确定哪个功能最简单。

我希望这是有道理的。我有点陌生Javascript,我意识到我已经深入研究了,但学习是有趣的部分;-)
如果需要,我可以提供更多代码或 JSFiddle。

4

1 回答 1

1

使用下划线any并使all这相对容易。这是它的要点:

  var toWords = function(text) {
    //Do any fancy cleanup and split to words
    //I'm just doing a simple split by spaces.
    return text.toLowerCase().split(/\s+/);
  };

  var partialMatch = function(original, fragment) {   
    //get the words of each input string
    var origWords = toWords(original + ""), //force to string
        fragWords = toWords(fragment);

    //if all words in the fragment match any of the original words, 
    //returns true, otherwise false
    return _.all(fragWords, function(frag) {
      return _.any(origWords, function(orig) {
        return orig && orig.indexOf(frag) >= 0;
      });
    });
  };

  //here's your original filterTable function slightly simplified
  var filterTable = function(collection, filterValue) {
      if (filterValue === "") {
          return collection.toJSON();
      }
      return collection.filter(function(data) {
          return _.some(_.values(data.toJSON()), function(value) {
              return partialMatch(value, filterValue);
          });
      });
  };

注意:这种方法的计算效率非常低,因为它首先需要遍历集合中的所有项目,然后是每个项目的所有字段,然后是该项目值中的所有单词。此外,循环内部声明了一些嵌套函数,因此内存占用不是最佳的。如果您有一小部分数据,那应该没问题,但如果需要,可以进行许多优化。如果我有时间,我可能会稍后回来并稍微编辑一下。

/代码示例未测试

于 2013-01-14T16:51:35.450 回答