Knockout.js显示/隐藏块可见性模式

时间:2013-02-18 09:01:30

标签: javascript design-patterns knockout.js dry

在下一种情况下,我有代码重复问题。在我的页面上,我需要通过点击链接显示/隐藏很多块:

<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/

问题如何避免所有这些节目/可见重复?也许我需要一些自定义绑定,我把我的隐藏块或smth的id。其他?您可以建议的任何模式?

3 个答案:

答案 0 :(得分:4)

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

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/

答案 1 :(得分:3)

您可以将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字符串。

答案 2 :(得分:1)

为什么不使用带有一些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/

相关问题