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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14932600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 18:22:42  来源:igfitidea点击:

Knockout.js show / hide block visibility pattern

javascriptdesign-patternsknockout.jsdry

提问by Akim Khalilov

I have the code duplication problemin the next case. On my page I have a lot of blocks that I need to show / hide by clicking to link:

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

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

And my JS

还有我的 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());

Here is jsfiddle example http://jsfiddle.net/sstude/brCT9/2/

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

Questionis how to avoid all this show / visible duplication? Maybe I need some custom binding where I put id of my hidden block or smth. else? Any patterns that you can suggest?

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

采纳答案by RP Niemeyer

Here was a thought at encapsulating this functionality completely in an observable for your specific scenario:

这是将这个功能完全封装在您的特定场景的 observable 中的想法:

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 });
        }
    }
};

It could be tweaked further, as necessary, if maybe the value passed into the binding should matter.

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

Example: http://jsfiddle.net/rniemeyer/gCgy5/

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

回答by Fabian Schmengler

You could use a templatetogether with a separate model for the hidden elements:

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

HTML

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

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');
};

Note: for just these two elements this might be too much overhead but as soon as you need more hidden items, it pays off. Any additional element needs just one short line of HTML and JS each.

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

UPDATE FOR COMPLEX TEMPLATE WITH BINDINGS:

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

If your HTML content contains bindings itself you can put it into templates too and load these dynamically

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

Working Example

工作示例

HTML

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

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');
};

contentis now the template id instead of an HTML string.

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

回答by Grim

Why not use an observableArray with some ids (one for each checkbox)?

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

You could then have methods like:

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

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

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

And in your binding:

在你的绑定中:

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

Edit: i updated your fiddle to show a possible implementations: http://jsfiddle.net/brCT9/4/

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