【问题标题】:knockout toggle visibility of nested items嵌套项目的淘汰赛切换可见性
【发布时间】:2014-03-19 13:36:16
【问题描述】:

我正在尝试使用 Knockout 切换嵌套项目的可见性。在页面的初始显示上,我不希望嵌套项目可见。如果用户单击链接以显示嵌套项,那么我希望显示这些嵌套项(不是所有嵌套项)。

例如,我有一个产品列表,对于每个产品,我都有一个星级列表。默认情况下或对于初始页面加载,评级不显示。如果用户单击“评分”,则显示该项目的评分。如果用户单击另一个项目的“评分”,则该产品的评分将与另一个一样显示。

为了说明,我有两个产品:

三星评分

iPhone 评分

如果我点击 iPhone 的评级,则会显示 iPhone 的评级:

Samsung Ratings       
iPhone Ratings
    1203: 3
    1204: 2

如果我点击三星的评级,那么三星的评级也会显示:

Samsung Ratings
    1201: 5
    1202: 4
iPhone Ratings
    1203: 3
    1204: 2

然后,如果我单击任一产品的评级,该产品的评级将变得不可见。

我的示例 HTML 如下:

<ul data-bind="foreach: products">
    <li><span data-bind="text: ProductName"></span>
        <a href="#" data-bind="click: $parent.toggleVisibility">Ratings</a> 
        <ul data-bind="foreach: StarRatings, visible: $parent.shouldShowRatings">
            <li><span data-bind="text: RatingId"></span>: <span data-bind="text: RatingValue"></span></li>
        </ul>
        </li>
</ul>

使用 Knockout.js 3.0.0 的示例 javascript 如下:

var initialProducts = [{ 
    ProductName: "Samsung", 
    StarRatings: [{ 
        RatingId: 1201, 
        RatingValue: 5
        },
        { 
            RatingId: 1202, 
            RatingValue: 4
        }
    ]
}, {
    ProductName: "iPhone", 
    StarRatings: [{ 
        RatingId: 1203, 
        RatingValue: 3
        },
        { 
            RatingId: 1204, 
            RatingValue: 2
        }
    ]
}];

(function (ko) {
    function products(data) {

        var self = this;
        data = data || {};

        // Persisted properties
        self.ProductId = data.ProductId;       
        self.StarRatings = data.StarRatings;
    }    
})(ko);

var viewModel = (function(ko){
    var products = ko.observableArray(initialProducts),
        showRatings = ko.observableArray(),
        toggleVisibility = function(item) {
            if(showRatings.indexOf(item) < 0){
                showRatings.push(item);
            } 
            else{
                showRatings.remove(item);
            }
        },
        shouldShowRatings = function(item) {
            if( showRatings.indexOf(item) >= 0){
                return true;
            }
            {
                return false;
            }
        };

    return {
        products: products,
        showRatings: showRatings,
        toggleVisibility: toggleVisibility,
        shouldShowRatings: shouldShowRatings
    };
})(ko);

ko.applyBindings(viewModel);

我可以显示所有评级或不显示。我还能够将其设置为一次只显示一个,但我认为这段代码最接近我需要的解决方案。

看起来在点击事件之后,shouldShowRatings 对于 StarRatings 可见性没有调用可见性。

示例代码也在 jsFiddle 上 http://jsfiddle.net/justinnafe/866my/4/

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

    只需更新您的绑定以调用以 $data 作为第一个参数的函数:http://jsfiddle.net/866my/6/

    <ul data-bind="foreach: products">
        <li><span data-bind="text: ProductName"></span>
            <a href="#" data-bind="click: $parent.toggleVisibility($data)">Ratings</a> 
            <ul data-bind="foreach: StarRatings, visible: $parent.shouldShowRatings($data)">
                <li><span data-bind="text: RatingId"></span>: <span data-bind="text: RatingValue"></span></li>
            </ul>
        </li>
    </ul>
    

    重要的部分是您使用函数符号来获取绑定以检查更新。

    【讨论】:

    • 为什么页面加载时会触发点击事件?我需要让最初不可见。关于如何做到这一点的任何想法?
    • 我能找到的关于为什么在页面加载时触发点击事件的最佳解释是对象文字在页面加载时得到评估 (stackoverflow.com/questions/19276164/…);但是,我相信我正在使用自调用函数,并且需要将点击事件包装在匿名函数中。 jsfiddle.net/justinnafe/866my/9
    【解决方案2】:

    修复初始评估的更好方法是使用标准 ko 方式: http://jsfiddle.net/866my/10/

    改变

    <a href="#" data-bind="click: $parent.toggleVisibility($data)">Ratings</a>
    

    <a href="#" data-bind="click: $parent.toggleVisibility">Ratings</a>
    

    现在 ko 得到一个函数对象(toggleVisibility 函数),在你点击它之前它不会调用该函数。

    ko 默认将当前上下文 $data 作为第一个参数传递给目标函数,因此不需要显式调用($data)。

    【讨论】:

      猜你喜欢
      • 2013-07-07
      • 1970-01-01
      • 1970-01-01
      • 2018-06-21
      • 2014-12-11
      • 2011-08-11
      • 2015-06-02
      • 2014-06-08
      • 2014-08-08
      相关资源
      最近更新 更多