在knockoutjs中绑定两次自定义处理程序



我已经编写了一个自定义绑定处理程序来显示在knockout中的引导弹出窗口:

ko.bindingHandlers.popover = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        $(element).popover({
            html: true,
            content: function () { return $('#' + ko.unwrap(valueAccessor().template)).html(); },
            placement: "right",
            trigger: "manual",
            container: 'body'
        });
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        if (valueAccessor().visible()) {
            $(element).popover('show');
            var popover = $("body .popover").last().get(0);
            ko.cleanNode(popover);
            ko.applyBindings(bindingContext.$rawData, popover);
        } else
            $(element).popover('hide');
    }
};

但是,当我尝试在同一个元素上绑定它两次时,像这样:

<input type="password" class="form-control" id="login-password" placeholder="Password" data-bind="textInput: login.password.input, hasFocus: login.password.focus, popover: { visible: login.showBadPassword, placement: 'right', template: 'bad-password-popover' }, popover: { visible: login.showThrottled, placement: 'right', template: 'throttled-popover' }" />

…它只结合了第二个。我猜这是因为它覆盖了第一个。

是否有一种方法可以绑定相同的东西两次?

有一个基本的问题,那就是你一次只能显示一个弹出窗口。你可以使用一些技术在单个元素中支持多个弹出窗口,但这不是标准的。

如果你考虑到一次只能看到一个弹出窗口的限制,你可以使用这样的自定义绑定处理程序:

ko.bindingHandlers.popover = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
		var values = ko.unwrap(valueAccessor());
        values.forEach(function(value) { value.visible(); });
        debugger;
        var visibleValue = values.find(function(value) { return value.visible();});
        
        if (visibleValue) {
            $(element).popover('destroy');
            $(element).popover({
                html: true,
                content:  $('#' + ko.unwrap(visibleValue.template)).html(),
                placement: ko.unwrap(visibleValue.placement),
                container: 'body'
            });
            $(element).popover('show');
            var popover = $("body .popover").last().get(0);
            ko.cleanNode(popover);
            ko.applyBindings(bindingContext.$rawData, popover);
        } else {
            $(element).popover('hide');
        };
    }
};
var vm = {
    triggerA: ko.observable(),
    triggerB: ko.observable()
}
ko.applyBindings(vm);
<link href="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="password"  
       data-bind="popover: 
                  [{visible: triggerA, placement: 'right', template: 'A'},
                  {visible: triggerB, placement: 'right', template: 'B'}]"/>
<script type="text/html" id="A">
    This is popover <b>A</b>
</script>
<script type="text/html" id="B">
    This is popover <b>B</b>
</script>
<br/>
<label>Trigger A<input type="checkbox" name="triggers" data-bind="checked: triggerA"></label>
<label>Trigger B<input type="checkbox" name="triggers" data-bind="checked: triggerB"></label>

在这个示例实现中,你可以指定几个不同的弹出窗口配置,但可见的将是第一个可见的可观察对象为真。您可以通过以下几种方式修改此脚本:

  • 在同一个弹出窗口中包含多个div,并使用不同的可见观察对象控制它们的可见性。这应该在init中完成,update中的代码应该停止破坏和重新创建弹出窗口
  • 使用一些可用的技术在同一个元素中显示多个弹出窗口
  • 忘记这个实现,并使用不可见的元素与你原来的弹出窗口在每个

如果你传递一些"popoverId"作为绑定参数,你可以在数据中存储特定的弹出窗口:

var newPopover = $(element).popover({ /* some potions */ });
$(element).data(ko.unwrap(valueAccessor().popoverId, newPopover);
在init中

并在update:

中获取弹出窗口
var popover = $(element).data(valueAccessor().popoverId);

最新更新