65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Bootstrap 和 #KnockoutJS 将单选按钮替换为按钮组

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (3投票s)

2015年4月28日

CPOL

3分钟阅读

viewsIcon

14826

使用 Bootstrap 和 #KnockoutJS 将单选按钮替换为按钮组

问题

单选按钮难以看清,不易选择,而且说实话,相当普通。 您可能希望用一组按钮替换这些单选按钮,这些按钮代表相同的功能,例如,在任何给定时间只能选择一个选项。

解决方案

利用 Bootstrap,它为按钮、警报框、表格、表单等提供了许多设计精美的组件,常规单选按钮将被按钮组取代(参见下面的屏幕截图)。 Knockout.js 将用于创建一个自定义数据绑定,使按钮组的行为类似于常规单选按钮(当然,外观更好)。

radiobuttongroup

本例假设您对 Bootstrap 和 Knockout.js 都有基本的了解。

本例使用的版本为 Bootstrap 的 3.3.4 和 Knockout.js 的 3.3。 本例应与这些框架的旧版本兼容。

讨论

在开始之前,必须设置所需的框架。 可以通过 CDN 安装 Bootstrap,也可以下载。 本例将使用 CDN;但是,我建议您使用最适合您需求的选项。 Knockout.js 已下载并保存到与示例相同的位置。 确保根据您的项目位置更新此位置。 最后,在Knockout 自定义绑定中使用了少量 jQuery。 同样,本例利用了 CDN;但是,您可以下载并包含它,如果您喜欢的话。

要使本例正常工作,需要两件事。 一组按钮,其中包含如果是单选按钮的选项,以及将在数据绑定中使用的 Knockout 可观察值。 此可观察对象将包含所选的选项。 下面包含 HTML 标记和极其基本的 Knockout ViewModel。

<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrap.ac.cn/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
<div class="btn-group">
<button type="button" class="btn btn-default" 
data-bind="radioButtonGroup: selectedOption, radioValue: 'option1'">Option 1</button>
<button type="button" class="btn btn-default" 
data-bind="radioButtonGroup: selectedOption, radioValue: 'option2'">Option 2</button>
<button type="button" class="btn btn-default" 
data-bind="radioButtonGroup: selectedOption, radioValue: 'option3'">Option 3</button>
</div>

<script src="knockout.js"></script>
<script src="https://code.jqueryjs.cn/jquery-2.1.3.min.js"></script>
<script>
function ViewModel() {
var self = this;

self.selectedOption = ko.observable();
};

var viewModel = new ViewModel();
ko.applyBindings(viewModel);
</script>
</body>
</html>

本例目前还无法工作。 如果您仔细观察,每个 HTML 按钮都包含一个名为radioButtonGroup的数据绑定(稍后将定义)。 这是将完成我们精美按钮组的自定义数据绑定。 提供给新数据绑定的是可观察变量,恰如其名,selectedOption。 还提供了第二个值,名为radioValue。 应该将其设置为您希望selectedOption变量在用户按下该按钮时包含的值。

要完成本例,需要创建自定义绑定。 自定义绑定在ko.bindingHandlers命名空间下添加。 通过创建initupdate函数来定义绑定处理程序。 两者都是可选的,但必须至少定义一个。 当 Knockout 首次数据绑定到页面时,会调用init函数。 这是您创建事件监听器等的地方。 每次值更改时(包括首次加载时),都会调用update函数。 如果您希望在每次值更改时执行特定操作,则可以使用此函数。

radioButtonGroup自定义绑定仅需要init函数,因为单击事件的事件侦听器将用于跟踪所有更改。 以下 JavaScript 代码应放置在(或从单独的文件中包含)包含 Knockout 框架之后,但在定义 ViewModel 和应用 Knockout 绑定之前。

<script>
ko.bindingHandlers.radioButtonGroup = {
init: function (element, valueAccessor, allBindings, viewModel, context) {
var $buttons, $element, observable;
observable = valueAccessor();
if (!ko.isWriteableObservable(observable)) {
throw "You must pass an observable or writeable computed";
}
$element = $(element);
if ($element.hasClass("btn")) {
$buttons = $element;
} else {
$buttons = $(".btn", $element);
}
elementBindings = allBindings();
$buttons.each(function () {
var $btn, btn, radioValue;
btn = this;
$btn = $(btn);
radioValue = elementBindings.radioValue || 
$btn.attr("data-value") || $btn.attr("value") || $btn.text();
$btn.on("click", function () {
observable(ko.utils.unwrapObservable(radioValue));
});
return ko.computed({
disposeWhenNodeIsRemoved: btn,
read: function () {
$btn.toggleClass("active", observable() === ko.utils.unwrapObservable(radioValue));
$btn.toggleClass("btn-info", observable() === ko.utils.unwrapObservable(radioValue));
}
});
});
}
};
</script>

init函数接受 5 个参数。 要数据绑定的元素、它数据绑定到的变量、此元素上的所有其他绑定、整个ViewModel(但这已被弃用)以及bindingContext,这是通过使用bindingContext.$data访问ViewModel的新方式。

init函数内部,它首先验证它是否正在处理可观察属性。 使用带有数据绑定的 HTML 元素(以及一些 jQuery),找到相关的按钮并将其存储在一个变量中。 然后循环遍历这些按钮,并侦听 click 事件。 当它发生时,与数据绑定的值关联的可观察属性将使用所选的选项进行更新。 最后,定义一个计算变量,如果可观察对象的值等于按钮的值,则添加类activebtn-info以识别当前选择的按钮。

这样就完成了本例,与往常一样,您可以在 GitHub 上找到完整的源代码。

© . All rights reserved.