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

Knockout Code with KnockoutJS

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (2投票s)

2015年11月17日

CPOL

6分钟阅读

viewsIcon

13134

downloadIcon

111

快速上手数据绑定和 KnockoutJS。

如果您最近在进行任何客户端 JavaScript 编码,尤其是单页应用程序,那么不利用至少一种可用的 JavaScript 库或框架将会是疯狂的。这些库的主要好处之一就是数据绑定,特别是双向数据绑定。实现双向声明性数据绑定可以显著减少您的代码量,并使您的 Web 应用程序更易于阅读和理解。

实现双向数据绑定的两个最知名的库是 AngularJS 和 KnockoutJS。虽然 AngularJS 越来越受欢迎,并且提供了比 KnockoutJS 多得多的功能,但它无疑更复杂,更难上手,并且在某种程度上将您(开发者)束缚在它自己的框架或架构中。另一方面,KnockoutJS 主要只做一件事:数据绑定,而且做得很好。然而,正如您将看到的,这一件事可以极大地影响您的 Web 应用程序的可读性和可维护性。

HTML 和 JavaScript 的数据绑定在本质上是一个非常简单的概念。它提供了一种将 DOM 元素(HTML)与 JavaScript 对象或变量关联起来的方法,并使它们保持同步,以便当其中一个发生变化时,相关的实体也会自动发生变化。例如,当用户编辑与 JavaScript 变量(或数据位置)绑定的 <input> HTML 元素的值时,变量也会被更新。您无需编写代码,例如在页面提交时,查找正确的 DOM 元素并将相应的值复制到 JavaScript 变量或对象中。

现在您已经对数据绑定有了基本了解,让我们更实际一些,编写一些代码来利用 KnockoutJS 的优势。我们将从一个实际上只代表单向数据绑定的简单示例开始。

<!DOCTYPE html>
<html>
<head>
    <title></title>
	<meta charset="utf-8" />

    <script type="text/javascript" src="jquery-1_11_2_min.js"></script>
    <script type="text/javascript" src="knockout-3.3.0.js" ></script>

    <script>

        var theViewModel = null;

        $(document).ready(function ()
        {
            theViewModel = ViewModel();
            ko.applyBindings(theViewModel);
        });

        function ViewModel()
        {
            var self = this;
            self.FirstName = "Tom";
            self.LastName = "Brady";
            return self;
        }

        function firstName_OnBlur()
        {
            alert(theViewModel.FirstName);
        }

    </script>
</head>
<body>
    <div>
        <label>First Name:</label>
        <input type="text" data-bind="value: FirstName" onblur="firstName_OnBlur();" />
    </div>
    <div>
        <label>Last Name:</label>
        <input type="text" data-bind="value: LastName" />
    </div>
</body>
</html>

上面的示例中有三个特定于 KnockoutJS 的项。其中两个是两个 <input> HTML 元素上的 data-bind 属性,它们以声明方式将元素绑定到 JavaScript。data-bind 属性将始终由相关元素的属性名称后跟冒号以及属性应绑定的 JavaScript 组成(您也可以在同一个属性中绑定多个属性)。此 JavaScript 可以是 JavaScript 表达式,但通常是对象属性。

第三个特定于 KnockoutJS 的项是在 $(document).ready 函数中调用 ko.applyBindings 函数。applyBindings 函数告诉 KnockoutJS 将 UI 与给定的 JavaScript 对象关联起来。在此示例中,任何 HTML 元素都可以绑定到 ViewModel 对象的任何属性。但是,可以通过将一个元素作为第二个参数传递给 ko.applyBindings 来将多个 JavaScript 对象与页面的不同部分关联起来。默认情况下,当第二个参数为空时,绑定将应用于整个页面。

当您运行上面的示例时,您会注意到“名字”输入元素的 blur 事件处理程序中的警报将始终显示文本框的原始值,在本例中为“Tom”。这是因为上面的示例仅实现了单向数据绑定。实现双向绑定就像调用 KnockoutJS 库上的一个函数一样简单,该函数指示绑定应该是“可观察的”(observable),这意味着当相应的实体更新时,相关实体应该被通知和更新。将 ViewModel 函数替换为以下代码:

        function ViewModel()
        {
            var self = this;
            self.FirstName = ko.observable("Tom");
            self.LastName = ko.observable("Brady");
            return self;
        }

如果您希望 UI 元素具有双向绑定,则应该调用 observable 函数。单个参数是默认值。现在,如果您使用修改后的 ViewModel 函数运行示例,firstName_OnBlur 函数中的警报将通过 JavaScript 对象变量显示 <input> 元素的更新值。另外需要注意的是,当您“观察”一个对象时,KnockoutJS 实际上会为底层 JavaScript 对象创建一个函数。因此,要访问对象(或变量)的值,您需要将其视为一个函数,在对象末尾加上“()”。在上面的示例中,对“alert”的调用将如下更改:

alert(theViewModel.FirstName());

设置对象的值也类似,您需要将值作为参数提供给函数,如下所示:

theViewModel.FirstName(‘Bill’);

这是 KnockoutJS 中唯一的“陷阱”,而且我认为它的实现方式是为了支持所有版本的 JavaScript 和浏览器。

任何开发者接下来可能提出的逻辑问题是:“如何实现迭代绑定,以便动态的 HTML 元素列表可以绑定到 JavaScript 对象列表(或数组)?”这几乎同样简单。您不需要调用‘observable’函数,而是调用 KnockoutJS 中的 observableArray 函数,如下面的示例所示。

<!DOCTYPE html>
<html>
    <head>
        <title></title>
	    <meta charset="utf-8" />

        <script type="text/javascript" src="jquery-1_11_2_min.js"></script>
        <script type="text/javascript" src="knockout-3.3.0.js" ></script>

        <script>

            var theViewModel = null;

            $(document).ready(function ()
            {
                theViewModel = ViewModel();
                ko.applyBindings(theViewModel);
            });

            function Car(make, model)
            {
                var self = this;
                self.Make = ko.observable(make);
                self.Model = ko.observable(model);
            }
            function ViewModel()
            {
                var self = this;
                self.Cars = ko.observableArray([
                    new Car("Honda", "CR-V"),
                    new Car("Toyota", "Sienna"),
                    new Car("Ford", "Explorer")
                ]);

                self.onClick = function ()
                {
                    alert(this.Make() + ' ' + this.Model());
                };

                return self;
            }

        </script>
    </head>
    <body>
        <div>
            <label>Colors:</label>
            <table>
                <thead>
                    <tr>
                        <th>Make</th>
                        <th>Model</th>
                    </tr>
                </thead>
                <tbody data-bind="foreach: Cars">
                    <tr data-bind="click: onClick">
                        <td><input data-bind="value: Make" /></td>
                        <td><input data-bind="value: Model" /></td>
                    </tr>
                </tbody>
            </table>
        </div>
     </body>
</html>

此示例中有几点需要注意。<tbody> 元素的 data-bind 中的 foreach 关键字是 KnockoutJS 遍历数组的方式。默认情况下,任何后代 HTML 元素都绑定到数组中的元素,而不是父对象(在本例中为 ViewModel),这解释了为什么我们可以在 data-bind 属性中引用 Make 和 Model 属性。

另一项需要注意的是表行元素的数据绑定中对“click”的引用。KnockoutJS 还允许您将某些事件绑定到数据模型中的函数。在上面的示例中,我们将 ViewModel(在本例中为父级)中的 onClick 函数与每个表行的 click 事件关联起来。在这种情况下,函数内部由“this”引用的作用域是数组元素本身。

您会在上面的两个示例中注意到,任何 HTML 元素都没有分配“id”或“name”属性。这是因为没有必要。如果您正确地实现了数据绑定,您的 JavaScript 代码就不需要引用 DOM 中的任何元素。相反,您将引用 JavaScript 变量/对象来获取这些元素的值。KnockoutJS 会处理其余的事情。

KnockoutJS 中还有一项我想要指出的功能,名为“计算可观察项”(computed observables),它真正地扩展了该库的实用性和强大功能,以及数据绑定的强大功能。此功能提供了一种使用多个可观察项来实现双向数据绑定的方法。具体来说,它允许您将 JavaScript 函数与 DOM 元素关联起来,而不是变量或对象属性,以便该值可以被“计算”出来,而不是仅仅被分配。

作为计算可观察项的一个例子,我们可以使用上面的第一个演示,并向 ViewModel 对象添加一个 FullName 属性,该属性通过连接姓和名属性(当然,中间有一个空格)来计算得出,如下所示:

function ViewModel()
{
    var self = this;
    self.FirstName = ko.observable("Tom");
    self.LastName = ko.observable("Brady");
    self.FullName = ko.computed(function ()
    {
        return self.FirstName() + " " + self.LastName();
    });
    return self;
}

通过修改 firstName_OnBlur 事件函数以显示全名,我们可以测试新的 FullName 可观察项,如下所示:

function firstName_OnBlur()
{
    alert(theViewModel.FullName());
}

熟悉创建单页 Web 应用程序的开发者应该能够理解 KnockoutJS 库提供的强大功能,尤其是考虑到它的小巧的体积和有限的功能。虽然 KnockoutJS 还提供了更多功能,如自定义绑定、自定义元素和订阅更改,但本文涵盖了最重要和最强大的功能,应该能帮助您立即开始(数据)绑定。

© . All rights reserved.