【问题标题】:KnockoutJS - Sorting with IsotopeKnockoutJS - 用同位素排序
【发布时间】:2015-01-06 07:00:36
【问题描述】:

我正在尝试显示产品列表,并使用同位素使它们可排序。问题是,排序函数什么都不做,也不返回错误。此外,overflow:hidden 将应用于除第一个产品之外的所有产品。

JsFiddle:http://jsfiddle.net/tvx07j7c/

JS:

  var $container = $('#phoneCatalog-Container').isotope({
      itemSelector: '.phoneCatalog-Item',
      getSortData: {
          price: function ($elem) {
              return $elem.find('.phoneCatalog-Price').text();
          }
      }
  });

  $('.target').on('click', 'button', function () {
      $container.isotope({
          sortBy: price
      });
  });



  function Item(phoneID, phoneMake, phoneModel, phoneAlias, price) {
      this._phoneID = ko.observable(phoneID);
      this.phoneMake = ko.observable(phoneMake);
      this.phoneModel = ko.observable(phoneModel);
      this.phoneAlias = ko.observable(phoneAlias);
      this.price = ko.observable(Math.floor(Math.random() * 16) + 5);

      this.displayName = ko.computed(function () {
          return this.phoneMake() + " " + this.phoneModel();
      }, this);

  }
  // Animation callbacks for the planets list
  this.showPhoneElement = function (elem) {
      if (elem.nodeType === 1) $(elem).hide().fadeIn(700)
  }
  this.hidePhoneElement = function (elem) {
      if (elem.nodeType === 1) $(elem).fadeIn("fast", function () {
          $(elem).remove();
      })
  }


  sortBy = function (field) {
      console.log(field)
      this.filtereditems.sort(function (a, b) {
          return a[field] < b[field] ? -1 : 1;
      });
  };


  var viewModel = {
      items: ko.observableArray([]),
      selectedfilter: ko.observable(""),
      selectedBrand: ko.observable(""),
      selectedIndex: ko.observable(""),
      pageSize: ko.observable(3),
      pageIndex: ko.observable(0)

  };




  viewModel.filteredItems = ko.computed(function () {
      var filter = this.selectedfilter().toLowerCase();
      if (!filter) {
          var t = this.selectedBrand().toLowerCase();
          if (!t || t == "all") return this.items();
          return ko.utils.arrayFilter(this.items(), function (item) {
              return item.phoneMake().toLowerCase() == t;
          });
      }

  }, viewModel);

  viewModel.optionSelector = function (selector, data) {
      //option = selector;

      switch (selector) {
          case "brand":
              this.selectedfilter("");
              this.selectedIndex("");
              this.selectedBrand(data);
              break;
          case "index":
              this.selectedfilter("");
              this.selectedBrand("");
              this.selectedIndex(data);
              break;
          default:
              this.selectedfilter("");
              this.selectedIndex("");
              this.selectedBrand("all");
              break;
      }
  };


  var JSONdataFromServer = '[{"phoneID":"54a7a00bc6164c14deed643d","phoneMake":"Samsung","phoneModel":"x200","phoneAlias":"BuggyMorph","price":200},{"phoneID":"54a7a00b8d6650941f5a405f","phoneMake":"Nokia","phoneModel":"M592","phoneAlias":"BuggyMorph","price":300},{"phoneID":"54a7a00b4b93f209cabbdd33","phoneMake":"Motorola","phoneModel":"XT2042","phoneAlias":"BuggyMorph","price":300},{"phoneID":"54a7a00b3dec0d20713f8ca0","phoneMake":"LG","phoneModel":"XT2042","phoneAlias":"BeastlyPhone","price":300},{"phoneID":"54a7a00b69cca65ce8bf50ef","phoneMake":"Motorola","phoneModel":"x100","phoneAlias":"Triton","price":200},{"phoneID":"54a7a00baa7f43c455c07538","phoneMake":"Lenovo","phoneModel":"XT2042","phoneAlias":"BuggyMorph","price":200},{"phoneID":"54a7a00bd6ce0b095fd20ee4","phoneMake":"Motorola","phoneModel":"XT2042","phoneAlias":"BeastlyPhone","price":200},{"phoneID":"54a7a00bdde7b4ebb27d5e2f","phoneMake":"LG","phoneModel":"x200","phoneAlias":"BeastlyPhone","price":300},{"phoneID":"54a7a00b4eb0e09c9b47b64a","phoneMake":"Alcatel","phoneModel":"x100","phoneAlias":"BeastlyPhone","price":100},{"phoneID":"54a7a00bce4e8ea2e3936b55","phoneMake":"Apple","phoneModel":"x200","phoneAlias":"BeastlyPhone","price":200},{"phoneID":"54a7a00be1848cc46c3ee7c9","phoneMake":"Apple","phoneModel":"XT2042","phoneAlias":"BeastlyPhone","price":200},{"phoneID":"54a7a00b87ee74aa7b25e708","phoneMake":"LG","phoneModel":"x100","phoneAlias":"BuggyMorph","price":200},{"phoneID":"54a7a00b1f69852c1ba84ea5","phoneMake":"Samsung","phoneModel":"M592","phoneAlias":"Triton","price":300},{"phoneID":"54a7a00b4677c54e38af8d81","phoneMake":"Apple","phoneModel":"XT2042","phoneAlias":"Triton","price":200},{"phoneID":"54a7a00b0d2524cf57688eda","phoneMake":"Lenovo","phoneModel":"x100","phoneAlias":"BeastlyPhone","price":100}]';

  var dataFromServer = ko.utils.parseJson(JSONdataFromServer);

  //do some basic mapping (without mapping plugin)


  //     $.getJSON("/json/getPhoneCatalog", function (data) {
  //       var mappedData = ko.utils.arrayMap(data, function (item) {
  //          return new Item(item._phoneID, item.phoneMake, item.phoneModel, item.phoneAlias, item.price);
  //      });
  //        viewModel.items(mappedData);



  var dataFromServer = ko.utils.parseJson(JSONdataFromServer);

  //do some basic mapping (without mapping plugin)
  var mappedData = ko.utils.arrayMap(dataFromServer, function (item) {
      return new Item(item.phoneID, item.phoneMake, item.phoneModel, item.phoneAlias, item.price);
  });


  viewModel.items(mappedData);

HTML:

<div class='liveExample'> <span data-bind='text: filteredItems().length'>&nbsp;</span>

    <section> <strong>Filter: </strong>

        <input id="search" data-bind="value: selectedfilter, valueUpdate: 'afterkeydown'" />
    </section>
    <section id="Brand"> <strong>By Brand: </strong>
 <a href="#all" data-bind='click: function() {optionSelector("brand", "all")}'>All</a>
 <a href="#Apple" data-bind='click: function() {optionSelector("brand", "Apple")}'>Apple</a>
 <a href="#Samsung" data-bind='click: function() {optionSelector("brand", "Samsung")}'>Samsung</a>

    </section>
    <button class="target" data-sort-by="price">Sort by price</button>
    <div>
        <div id="phoneCatalog-Container" data-bind="template: {
                               foreach: filteredItems,
                               beforeRemove: hidePhoneElement,
                               afterAdd: showPhoneElement }" class="phoneCatalog-Item"> <span data-bind="text: phoneMake"></span>
 <span data-bind="text: phoneModel"> </span>
 <span data-bind="text:  '$' + price()" class="phoneCatalog-Price"> </span>

            <br />
        </div>
    </div>
</div>

JS:

【问题讨论】:

    标签: knockout.js jquery-isotope


    【解决方案1】:

    我对 isotope 不熟悉,但我快速浏览了他们的 doco,并且根据我对 Knockout 和 jQuery 插件的经验,我可以提出以下建议

    1. 您的排序点击处理程序不会触发。 $('.target').on('click', 'button', fn) 表示将单击事件附加到具有“目标”类的任何元素的所有按钮后代。这应该是$('button.target').on('click', fn)

    2. 当 if 触发时,您的 sortBy 参数应该是字符串 'price'

    3. Isotope 似乎可以扫描 DOM 并对父元素的所有子元素进行编目。当它最初加载时,模板绑定尚未触发,因为没有子级。每当 filteredItem observableArray 在初始绑定后更改AND时,您需要强制同位素重新加载子级。
      在所有 observables 都更新后,在 ko.applyBindings AND 之后立即添加 $container.isotope('reloadItems') 作为 optionSelector 函数中的最后一条语句。

    执行所有 3 项操作后,您的示例会出现另一个问题,即 Isotope 被配置为查找具有“phoneCatalog-Item”类的子元素,但该类位于您的“phoneCatalog-Container”元素上,而不是您的任何子元素重复。所以它仍然没有找到任何子元素。

    1. 您需要在 2 个跨度周围添加一个 DIV 包装器并移动“phoneCatalog-Item”css 类

    <div id="phoneCatalog-Container" data-bind="...">
      <div class="phoneCatalog-Item">
        <span>...
      </div>
    </div>
    

    另一个观察结果是,您将 jQuery 和 Knockout 混合用于 DOM 操作。每当 knockout 重建容器的所有子节点时,Isotope 插件将失去对所有(或部分)旧子节点的跟踪,但是当您通过 Isotope 排序时,它将重新排列 Knockout 创建的所有元素。

    理想情况下,您不应将两者混用。

    要么将排序功能移至已计算的过滤项目,要么将过滤功能移至同位素$container.isotope({ filter: ... })

    【讨论】:

      猜你喜欢
      • 2013-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-12
      相关资源
      最近更新 更多