【问题标题】:Knockout.js show / hide block visibility patternKnockout.js 显示/隐藏块可见性模式
【发布时间】:2013-02-18 09:01:30
【问题描述】:

在下一个案例中,我遇到了代码重复问题。在我的页面上,我需要通过单击链接来显示/隐藏很多块:

<div>
    <a data-bind="click: showHiddenFirst, visible: isVisibleFirst"href="#">Show first</a>
    <div data-bind="visible: !isVisibleFirst()" style="display:none">
        hidden content first
    </div>
</div>
<div>
    <a data-bind="click: showHiddenSecond, visible: isVisibleSecond"href="#">Show second</a>
    <div data-bind="visible: !isVisibleSecond()" style="display:none">
        hidden content second
    </div>
</div>

还有我的 JS

var vm = function(){
    this.isVisibleFirst = ko.observable(true);

    this.showHiddenFirst = function(){
        this.isVisibleFirst(false)
    };

    this.isVisibleSecond = ko.observable(true);

    this.showHiddenSecond = function(){
        this.isVisibleSecond(false)
    };
};

ko.applyBindings(new vm());

这是 jsfiddle 示例 http://jsfiddle.net/sstude/brCT9/2/

问题如何避免所有这些显示/可见的重复?也许我需要一些自定义绑定,在其中放置隐藏块的 id 或 smth。别的?你有什么可以推荐的模式吗?

【问题讨论】:

    标签: javascript design-patterns knockout.js dry


    【解决方案1】:

    以下是针对您的特定场景将此功能完全封装在可观察对象中的想法:

    ko.bindingHandlers.clickVisible = {
        init: function(element) {
           var visible = ko.observable(true),
               opposite = ko.computed(function() { return !visible(); }),
               clickHandler = visible.bind(null, false);
    
            //apply bindings to anchor
            ko.applyBindingsToNode(element, { click: clickHandler, visible: visible });
    
            var sibling = element.nextSibling;
            //find the div (as text nodes, etc. will show up in nextSibling)
            while (sibling && sibling.nodeType != 1) {
                sibling = sibling.nextSibling;   
            }        
    
            //apply bindings to div
            if (sibling) {
                ko.applyBindingsToNode(sibling, { visible: opposite });
            }
        }
    };
    

    如果可能传递给绑定的值很重要,可以根据需要进一步调整。

    示例:http://jsfiddle.net/rniemeyer/gCgy5/

    【讨论】:

      【解决方案2】:

      您可以将template 与隐藏元素的单独模型一起使用:

      HTML

      <div data-bind="template: { name: 'hidden-template', data: first }"></div>
      <div data-bind="template: { name: 'hidden-template', data: second }"></div>
      
      <script type="text/html" id="hidden-template">
          <a data-bind="click: showHidden, visible: isVisible, text : linkText" href="#"></a>
          <div data-bind="visible: !isVisible(), html: content" style="display:none"></div>
      </script>
      

      JS

      var hiddenModel = function(linkText, content) {
          this.linkText = linkText;
          this.content = content;
          this.isVisible = ko.observable(true);
          this.showHidden = function(){
              this.isVisible(false)
          };
      }
      
      var vm = function() {
          this.first = new hiddenModel('Show first', 'hidden content first');
          this.second = new hiddenModel('Show second', 'hidden content second');
      };
      

      注意:对于这两个元素,这可能开销太大,但只要您需要更多隐藏项目,它就会得到回报。任何额外的元素都只需要一行简短的 HTML 和 JS。

      带有绑定的复杂模板的更新:

      如果您的 HTML 内容本身包含绑定,您也可以将其放入模板并动态加载它们

      Working Example

      HTML

      <div data-bind="template: { name: 'hidden-template', data: first }"></div>
      <script type="text/html" id="content-first">
          test simple content
      </script>
      <div data-bind="template: { name: 'hidden-template', data: second }"></div>
      <script type="text/html" id="content-second">
          test content <a href="#" data-bind="click:testBtn">with binding</a>
      </script>
      
      <script type="text/html" id="hidden-template">
          <a data-bind="click: showHidden, visible: isVisible, text : linkText" href="#"></a>
          <div data-bind="visible: !isVisible(), template: { name: content, data: $parent }" style="display:none"></div>
      </script>
      

      JS

      var hiddenModel = function(linkText, content) {
          this.linkText = linkText;
          this.content = content;
          this.isVisible = ko.observable(true);
          this.showHidden = function(){
              this.isVisible(false)
          };
      }
      
      var vm = function() {
          this.testBtn = function(){alert('it works');}
          this.first = new hiddenModel('Show first', 'content-first');
          this.second = new hiddenModel('Show second', 'content-second');
      };
      

      content 现在是模板 ID,而不是 HTML 字符串。

      【讨论】:

      • 在我的生产示例中,div 的内容太复杂(很多带有 KO 绑定的 html),无法将其放入函数构造函数中。
      • 有什么想法可以通过data-bind="visibilityDependsOn: anotherValue"data-bind="visibilityTarget: someName" 实现吗?我非常感谢您的建议,并尝试与他们一起玩。
      【解决方案3】:

      为什么不使用带有一些 id 的 observableArray(每个复选框一个)?

      然后您可以使用以下方法:

      model hideElement = function(id) {
        model.hiddenElements.push(id);
      }
      
      model.showElement = function(id) {
        model.hiddenElements.remove(id);
      }
      

      在你的绑定中:

      <div data-bind="click: function() { hideElement('two') }, visible: !hiddenElements().contains('one')"></div>
      

      编辑:我更新了您的小提琴以显示可能的实现:http://jsfiddle.net/brCT9/4/

      【讨论】:

      • 我认为这是我们需要的方式,但通过绑定使其更具声明性。但是怎么做呢?
      猜你喜欢
      • 2015-05-25
      • 2011-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-18
      • 1970-01-01
      • 2017-07-31
      相关资源
      最近更新 更多