如何在KnockoutJs中使用bindingHandlers

时间:2014-05-30 05:56:03

标签: javascript jquery knockout.js

我正在构建一个需要一堆打开/关闭标签的移动应用。我正在尝试找到一种方法来使用bindingHandlers来减少代码量。但我似乎想念一些东西。这是我的小提琴。

http://jsfiddle.net/noppanit/4zRrZ/

这就是我所拥有的

<a href="javascript:void(0)" data-bind="click: expandCommentsRatings">Rating
    <div style="display:none" data-bind="visible: productCommentsRatingsVisiblity">
        <div class="rating" style="width: 85%">3.5 Stars Rating</div>
    </div>
</a>
<br/>
<a href="javascript:void(0)" data-bind="click: expandsReviews">Reviews
    <div style="display:none" data-bind="visible: productReviewsVisiblity">
        <div class="reviews">Reviews</div>
    </div>
</a>

var Model = function () {
    var productCommentsRatingsVisiblity = ko.observable(false);
    var productReviewsVisiblity = ko.observable(false);

    var expandCommentsRatings = function (item, event) {
        productCommentsRatingsVisiblity(!productCommentsRatingsVisiblity());
        if (productCommentsRatingsVisiblity() === false) {
            $(event.target).removeClass('expanded');
        } else {
            $(event.target).addClass('expanded');
        }
    };

    var expandsReviews = function (item, event) {
        productReviewsVisiblity(!productReviewsVisiblity());
        if (productReviewsVisiblity() === false) {
            $(event.target).removeClass('expanded');
        } else {
            $(event.target).addClass('expanded');
        }
    };

    return {
        productCommentsRatingsVisiblity: productCommentsRatingsVisiblity,
        productReviewsVisiblity: productReviewsVisiblity,
        expandCommentsRatings: expandCommentsRatings,
        expandsReviews: expandsReviews
    }
};

ko.applyBindings(Model());

如何减少重复,以便我可以将此代码重用于其他ViewModel。我之所以挣扎是因为我不知道如何动态地将productCommentsRatingsVisiblityproductReviewsVisiblity传递给allBindings。你需要知道这个名字才能得到它。

感谢。

3 个答案:

答案 0 :(得分:1)

很抱歉对此有迟到的回复,但我有一个使用bindingHandlers的解决方案。

小提琴在这里:http://jsfiddle.net/u3m7m/1/

我遵循了一个创建toggle bindingHandler的策略,如果元素上没有它,则添加指定的类,如果是,则删除该类。实现此目的所需的唯一状态是元素上的类列表,这意味着您可以从模型中删除所有这些状态跟踪可观察对象。事实上,这是我使用的模型:

var Model = function () {
   // stuff
};

ko.applyBindings(Model());

toggle bindingHandler如下所示:

ko.bindingHandlers['toggle'] = {
    init: function (element, valueAccessor) {
        var value = ko.unwrap(valueAccessor()),
            clickHandler = function (e) {
                if (!e) {
                    e = window.event;
                }
                e.cancelBubble = true;
                if (e.stopPropagation) {
                    e.stopPropagation();
                }

                var classes = (this.className||'').split(' '),
                    index   = classes.indexOf(value);

                if (index >= 0) {
                    classes.splice(index, 1);
                } else {
                    classes.push(value);
                }

                element.className = classes.join(' ');
            };

        element.onclick = clickHandler;
        if (element.captureEvents) {
            element.captureEvents(Event.CLICK);
        }
    }
};

希望不会太复杂,e对象的奇怪外观来自此处:http://www.quirksmode.org/js/introevents.html

因为我使用的是仅使用类的策略,所以我必须添加到CSS中:

.expandable > div
{
    display: none;
}

.expandable.expanded > div
{
    display: block;
}

现在从html中删除了状态跟踪,并修改了data-bind以使用toggle bindingHandler:

<a class="expandable" href="javascript:void(0)" data-bind="toggle: 'expanded'">Rating
    <div>
        <div class="rating" style="width: 85%">3.5 Stars Rating</div>
    </div>
</a>
<br/>
<a class="expandable" href="javascript:void(0)" data-bind="toggle: 'expanded'">Reviews
    <div>
        <div class="reviews">Reviews</div>
    </div>
</a>

希望这对你有所帮助。

答案 1 :(得分:0)

我不确定这会对你有所帮助,

我根据您的需要重建和优化您的代码。

这可能会给你一些想法。您不需要自定义绑定处理程序来实现此功能。

这里有工作的jsFiddle:http://jsfiddle.net/farizazmi/6E4Wz/2/

所以,您需要包含属性来控制项目的可见性:

var data = [
    {
        'name' : 'test1',
        'rateIsExpanded' : ko.observable(false),
        'rating': 3.5,
        'review': 'blabla1',
        'reviewIsExpanded': ko.observable(false)
    },
    {
        'name' : 'test2',
        'rateIsExpanded' : ko.observable(false),
        'rating': 1.5,
        'review': 'blabla2',
        'reviewIsExpanded': ko.observable(false)
    }
];

并创建一个函数将用于改变每个数据的可见性状态:

var Model = function () {
   var self = this;

    self.data = ko.observableArray(data);

    self.expandRate = function(item)
    {
        console.log(ko.toJSON(item));
        item.rateIsExpanded( ! item.rateIsExpanded() );
    };

    self.expandReview = function(item)
    {
        item.reviewIsExpanded( ! item.reviewIsExpanded() );
    };

};

ko.applyBindings(Model());

答案 2 :(得分:0)

您只需使用observableArray来保存您的菜单系统,即可使用以下属性执行此操作:

  • itemName - 保存顶级菜单项
  • expanded - 控制带子项目的子菜单的扩展
  • subMenu - 举行儿童用品

除此之外,您需要一个简单的功能来在单击父级时切换每个子菜单的可见性。然后,您可以在数据绑定中使用knockout visible属性,该属性将绑定到expanded属性。

这是一个有用的 JSFiddle ,以下是使用的代码:

JS查看模型:

var Model = function () {    
    var self = this;
    self.tabs = ko.observableArray([
                    { itemName: "Ratings", 
                      expanded: ko.observable(false), 
                      subMenu: ["option 1","option 2"]},
                    { itemName: "Review", 
                      expanded: ko.observable(false), 
                      subMenu: ["option 1","option 2"]}
                ]);

    self.toggleExpanded = function (item) {
        item.expanded(!item.expanded());
    }    
};

ko.applyBindings(Model());

HTML Mark Up:

<ul data-bind="foreach: tabs">
    <li><span data-bind="text: itemName, click: toggleExpanded"></span>:
        <ul data-bind="foreach: subMenu">
            <li data-bind="text: $data, visible: $parent.expanded">
            </li>
        </ul>
    </li>
</ul>