创建没有业务逻辑的干净挖空绑定(弹出框 - 单选按钮)

Creating a clean Knockout binding without business logic (Popover - Radio Buttons)

本文关键字:绑定 单选按钮 业务 创建      更新时间:2023-09-26

我正在寻找一种干净的方法来实现以下内容。假设我有 5 个按钮:

(狗) - (猫) - (鱼) - (

鸟) - (其他)

在我的视图模型中,这些按钮表示为分类。因此,当我单击"狗"按钮时,视图模型中的可观察量应设置为"狗"(这将通过每个按钮上的单击绑定来完成)。

另外,我想在切换其中一个按钮时显示特定的样式(由按钮上的 css 绑定完成):

(狗) - (猫) - (鱼) - (

鸟) - (其他

所以现在看起来它应该将我的按钮变成单选按钮组。现在除此之外,当我单击"其他"按钮时,我还想显示一个小弹出窗口(引导程序),用户可以在其中指定自定义值,例如"Lion"。单击其他按钮将关闭弹出框。

现在,在每个按钮上,我可以添加一个类似于这个的绑定:

{ css: { 'toggled': classficationMatches('Dog') }, 
     popover: { action: 'close', id: 'mypopover' },
     click: { click:setClassification.bind($data, 'Dog') }

但这感觉很脏。我更喜欢构建一个自定义处理程序并像这样使用它:

{ toggleClassification: { type: 'Dog', popover: 'mypopover' } }

现在由 ViewModel 决定弹出框是否应该可见,并且绑定将包含向按钮添加 css 绑定、单击和弹出框绑定的所有逻辑。

我开始使用自定义绑定尝试一些事情,但这段代码看起来更糟:

ko.bindingHandlers["toggleClassification"] = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var classification = $(element).attr('data-type');
        var selector = ko.utils.unwrapObservable(valueAccessor());
        var pickerViewModel = new SimpleFilterSpecializationPickerViewModel(element, selector);
        // Whenever we click the button, show the popover.
        ko.utils.registerEventHandler(element, "click", function () {
            // Hide the popup if it was visible.
            if (pickerViewModel.isVisible()) {
                pickerViewModel.hide();
            }
            else {
                var requireInit = !pickerViewModel.loaded();
                // Show the popover.
                pickerViewModel.show();
                // The first time we need to bind the popover to the view model.
                if (requireInit) {
                    ko.applyBindings(viewModel, pickerViewModel.getPopoverElement());
                    // If the classification changes, we might not want to show the popover.
                    viewModel.isClassification(classification).subscribe(function () {
                        if (!viewModel.isClassification(classification)()) {
                            pickerViewModel.hide();
                        }
                    });
                }
            }
            $('button[data-popoverclose]').click(function () {
                $(element).popover('hide');
            });
        });
    }
};

ko.bindingHandlers["toggleClassification"] = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        // Store the current value on click.
        $(element).click(function () {
            var observable = valueAccessor();
            viewModel.setClassification(observable);
        }); 
        // Update the css of the button.
        ko.applyBindingsToNode(element, { css: { 'active': viewModel.isClassification(valueAccessor()) } }, viewModel);
    }
};

有人对如何清理绑定以便大多数"逻辑"可以在 ViewModel 中完成有一些提示吗?

可以通过编程方式
添加此"脏"绑定
ko.applyBindingsToNode(Element element, Object bindings, Object viewModel)例如
.HTML

data-bind="toggleClassification: { type: 'Dog', popover: 'mypopover' }"  

.JS

ko.bindingHandlers["toggleClassification"] = 
{
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) 
    {
        var type = valueAccessor().type;       // 'Dog'
        var popover = valueAccessor().popover; // 'mypopover'
        var binding = { 
                         css: { 'toggled': classficationMatches(type) }, 
                         popover: { action: 'close', id: popover },
                         click: { click:setClassification.bind(bindingContext.$data, type) }
                      };
        ko.applyBindingsToNode(element, binding , viewModel);
    }
};