Knockout components or templates performance gains

↘锁芯ラ 提交于 2019-12-02 07:50:27

I made a version of your fiddle that uses components to supply the input fields. The component used is named 'my-' plus whatever the type field is (this was necessary to distinguish my components from input and select tags). I don't know how well this will perform, but it's simple enough that you should be able to do some testing and see.

ko.components.register('my-input', {
  viewModel: InputModel,
  template: {
    element: 'input-template'
  }
});
ko.components.register('my-select', {
  viewModel: InputModel,
  template: {
    element: 'select-template'
  }
});
ko.components.register('my-mu', {
  viewModel: InputModel,
  template: {
    element: 'mu-template'
  }
});

function InputModel(params) {
  return params;
}


function Model() {
  records = ko.observableArray([
    [{
      type: "input",
      id: "Date",
      size: "100px",
      value: ko.observable()
    }, {
      type: "select",
      id: "Weather",
      size: "100px",
      value: ko.observable(),
      options: [{
        optId: "w1",
        optTxt: "Cloudy"
      }, {
        optId: "w2",
        optTxt: "Sunny"
      }, {
        optId: "w3",
        optTxt: "Rainy"
      }, {
        optId: "w4",
        optTxt: "Snowy"
      }, {
        optId: "w5",
        optTxt: "Foggy"
      }]
    }, {
      type: "input",
      id: "Lat",
      size: "80px",
      value: ko.observable()
    }, {
      type: "input",
      id: "Long",
      size: "80px",
      value: ko.observable()
    }],
    [{
      type: "input",
      id: "Date",
      size: "100px",
      value: ko.observable()
    }, {
      type: "select",
      id: "Temperature",
      size: "120px",
      value: ko.observable(),
      options: [{
        optId: "t0",
        optTxt: "<-10"
      }, {
        optId: "t1",
        optTxt: "]-10 : 0]"
      }, {
        optId: "t2",
        optTxt: "]0 : 20]"
      }, {
        optId: "t3",
        optTxt: "]20 : 40]"
      }, {
        optId: "t4",
        optTxt: ">40"
      }]
    }, {
      type: "select",
      id: "Wind",
      size: "70px",
      value: ko.observable(),
      options: [{
        optId: "wind1",
        optTxt: "Strong"
      }, {
        optId: "wind2",
        optTxt: "Weak"
      }]
    }],
    [{
      type: "input",
      id: "Date",
      size: "100px",
      value: ko.observable()
    }, {
      type: "select",
      id: "Weather",
      size: "100px",
      value: ko.observable(),
      options: [{
        optId: "w1",
        optTxt: "Cloudy"
      }, {
        optId: "w2",
        optTxt: "Sunny"
      }, {
        optId: "w3",
        optTxt: "Rainy"
      }, {
        optId: "w4",
        optTxt: "Snowy"
      }, {
        optId: "w5",
        optTxt: "Foggy"
      }]
    }, {
      type: "input",
      id: "Lat",
      size: "80px",
      value: ko.observable()
    }, {
      type: "input",
      id: "Long",
      size: "80px",
      value: ko.observable()
    }],
    [{
        type: "input",
        id: "Date",
        size: "100px",
        value: ko.observable()
      }, {
        type: "select",
        id: "Temperature",
        size: "120px",
        value: ko.observable(),
        options: [{
          optId: "t0",
          optTxt: "<-10"
        }, {
          optId: "t1",
          optTxt: "]-10 : 0]"
        }, {
          optId: "t2",
          optTxt: "]0 : 20]"
        }, {
          optId: "t3",
          optTxt: "]20 : 40]"
        }, {
          optId: "t4",
          optTxt: ">40"
        }]
      }, {
        type: "input",
        id: "Humidity",
        size: "70px",
        value: ko.observable(),
        options: [{
          optId: "wind1",
          optTxt: "Strong"
        }, {
          optId: "wind2",
          optTxt: "Weak"
        }]
      }, {
        type: "mu",
        id: null,
        value: '%'
      }

    ]
  ]);

}
var myModel = new Model();
ko.applyBindings(myModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<template id="select-template">
  <select data-bind="style: {width: size}, value: value, options: options, optionsText: 'optTxt', optionsValue: 'optId'"></select>
</template>
<template id="input-template">
  <input type="text" data-bind="style: {width: size}, value: value" />
</template>
<template id="mu-template"> <span data-bind="text: value"></span>

</template>
<div data-bind="foreach: records">
  <div data-bind="foreach: $data">
    <label data-bind="text: id"></label>
    <!-- ko component:{name:'my-'+type, params:$data} -->
    <!-- /ko -->
  </div>
</div>

From your Fiddle, I see that you render each field as an individual item. You could bypass all the if bindings if each item were presented the same, as a custom-bound text item that, when clicked, transforms into its editable field type.

If you want to preserve tabbing, the default presentation could be input, but upon focus, the appropriate field type displays.

Update: it occurs to me that you could even have your custom binding insert the appropriate input type into a bound div, so your presentation would be exactly as it is, but all the logic is in the custom binding.

I've made a Fiddle that dynamically inserts the inputs of appropriate types. It's a little rough, but gives the general idea of the approach. I don't know whether it's a performance advantage over the if bindings; it might just be doing the same things the hard way. Certainly the above suggestions of rendering as text or simple input and changing one field at a time when the user wants to edit would be faster on initial load.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!