KnockoutJS 3.X API 第六章 组件(3) 组件绑定

组件绑定将指定的组件注入到元素中,并且可选地将参数传递给它。

本节目录

  • 一个例子
  • API
  • 组件生命周期
  • 备注1:仅限模板组件
  • 备注2:使用没有容器元素的组件
  • 备注3:将标记传递给组件
  • 处置和内存管理

一个例子

First instance, without parameters
Second instance, passing parameters

UI源码:

<h4>First instance, without parameters</h4>
<div data-bind='component: "message-editor"'></div>
 
<h4>Second instance, passing parameters</h4>
<div data-bind='component: {
    name: "message-editor",
    params: { initialText: "Hello, world!" }
}'>
</div>

视图模型源码:

ko.components.register('message-editor', {
    viewModel: function(params) {
        this.text = ko.observable(params && params.initialText || '');
    },
    template: 'Message: <input data-bind="value: text" /> '
            + '(length: <span data-bind="text: text().length"></span>)'
});
 
ko.applyBindings();

注意:在更现实的情况下,通常从外部文件加载组件视图模型和模板,而不是将它们硬编码到注册中。

API

有两种方法使用组件绑定:

快速语法:

如果你只传递一个字符串,它被解释为一个组件名称。 然后注入命名的组件,而不向其提供任何参数。 例:

<div data-bind='component: "my-component"'></div>

也可以将监控属性作为组件名称。 在这种情况下,如果监控属性值更改,组件绑定将处理旧组件实例,并注入新引用的组件。 例:

<div data-bind='component: observableWhoseValueIsAComponentName'></div>

完整语法:

要向组件提供参数,请传递具有以下属性的对象:

  • name — 要注入的组件的名称。 同样,这可以是监控属性。
  • params —将被传递给组件的对象。 通常,这是一个包含多个参数的键值对象,通常由组件的viewmodel构造函数接收。

例如:

<div data-bind='component: {
    name: "shopping-cart",
    params: { mode: "detailed-list", items: productsList }
}'>
</div>

组件生命周期

当组件绑定注入组件时,

  1. 请求您的组件加载器提供viewmodel工厂和模板

    • 可以查阅多个组件加载器,直到第一个识别组件名称并提供视图模型/模板。 此过程仅对每个组件类型发生一次,因为Knockout在内存中缓存生成的定义。
    • 默认组件加载器根据您注册的内容提供viewmodels /template。 如果适用,这是从AMD加载器请求任何指定的AMD模块的阶段。

    通常,这是一个异步过程。 它可能涉及对服务器的请求。 对于API一致性,Knockout默认确保加载过程作为异步回调完成,即使组件已经加载并缓存在内存中。 有关更多信息以及如何允许同步加载,请参阅上一节的控制同步/异步加载。

  2. 组件模板被克隆并注入到容器元素中

    任何现有内容都将被删除并丢弃。

  3. 如果组件有一个viewmodel,它被实例化

    如果viewmodel是作为构造函数给出的,这意味着Knockout调用新的YourViewModel(params)。

    如果viewmodel作为createViewModel工厂函数给出,Knockout callscreateViewModel(params,componentInfo),其中componentInfo.element是尚未绑定的未绑定模板的元素。

    这个阶段总是同步完成(构造函数和工厂函数不允许是异步的),因为每次组件被实例化时都会出现这种情况,如果涉及等待网络请求,性能将是不可接受的。

  4. viewmodel被绑定到视图

    如果组件没有viewmodel,则视图将绑定到您提供给组件绑定的任何参数。

  5. 组件处于活动状态

    现在组件正在运行,并且可以在需要时保持在屏幕上。

    如果传递给组件的任何参数是监控属性,则组件当然可以观察到任何改变,或者甚至回写修改的值。 这是它如何能够干净地与其父进行通信,而不是将组件代码紧密地耦合到使用它的任何父进程。

  6. 组件被拆卸,并且视图模型被删除

    If如果组件绑定的名称值可观察地改变,或者如果封闭的控制流绑定导致容器元素被移除,则在从DOM移除容器元素之前调用视图模型上的任何dispose函数。 参见本节:处置和内存管理。

    注意:如果用户导航到完全不同的网页,浏览器会执行此操作,而不会要求页面中运行的任何代码进行清理。 所以在这种情况下不会调用dispose函数。 这是正常的,因为浏览器会自动释放所有使用的对象使用的内存。

 

备注1:仅限模板组件

组件通常有viewmodels,但它们不一定必须。 组件只能指定一个模板。

在这种情况下,组件视图所绑定的对象是您传递给组件绑定的params对象。 例:

ko.components.register('special-offer', {
    template: '<div class="offer-box" data-bind="text: productName"></div>'
});

...可以注入参数:

<div data-bind='component: {
     name: "special-offer-callout",
     params: { productName: someProduct.name }
}'></div>

或者,更方便地,作为自定义元素:

<special-offer params='productName: someProduct.name'></special-offer>

备注2:使用没有容器元素的组件

有时,您可能想要将一个组件注入到视图中,而不使用额外的容器元素。 您可以使用基于注释标签的无容器控制流语法。 例如,

<!-- ko component: "message-editor" -->
<!-- /ko -->

...或传递参数:

<!-- ko component: {
    name: "message-editor",
    params: { initialText: "Hello, world!", otherParam: 123 }
} -->
<!-- /ko -->

<!-- ko -- >和<!-- / ko -- >注释作为开始/结束标记,定义一个包含标记的“虚拟元素”。 Knockout理解这个虚拟元素的语法,并绑定,就像你有一个真正的容器元素。

备注3:将标记传递给组件

您附加组件绑定的元素可能包含进一步的标记。 例如,

<div data-bind="component: { name: 'my-special-list', params: { items: someArrayOfPeople } }">
    <!-- Look, here's some arbitrary markup. By default it gets stripped out
         and is replaced by the component output. -->
    The person <em data-bind="text: name"></em>
    is <em data-bind="text: age"></em> years old.
</div>

虽然此元素中的DOM节点将被删除,并且不会默认绑定,但它们不会丢失。 相反,它们被提供给组件(在这种情况下,my-special-list),它可以将它们包括在它希望的输出中。

如果要构建表示“容器”UI元素的组件(如网格,列表,对话框或标签集),这需要注入并将任意标记绑定到公共结构中,这将非常有用。 它也可以在没有自定义元素的情况下使用上面显示的语法。

处置和内存管理

您的viewmodel类可能具有dispose函数。 如果实现了,当组件被删除并从DOM中删除时,Knockout会调用它(例如,因为相应的项从foreach中删除,或者如果绑定变为false)。

您必须使用dispose释放任何本质上不可回收的资源。 例如:

  • setInterval 回调将继续触发,直到显式清除。
    • 使用clearInterval(handle)来停止它们,否则你的viewmodel可能被保存在内存中。
  • ko.computed属性继续从其依赖关系接收通知,直到明确处置。
    • 如果一个依赖是一个外部对象,那么一定要使用.dispose()在computed属性,否则它(可能还有你的viewmodel)将被保存在内存中。 或者,考虑使用pureComputed以避免手工处置的需要。
  • 监控属性订阅将继续运行,直到明确被处理。
    • 如果你订阅了一个外部的observable,一定要使用.dispose()在订阅,否则回调(可能还有你的viewmodel)将被保存在内存中。
  • 外部DOM元素上手动创建的事件处理程序(如果在createViewModelfunction中创建)(甚至在常规组件视图模型内部,尽管适合您不应该使用的MVVM模式)必须删除。
    • 当然,您不必担心在视图中释放由标准Knockout绑定创建的任何事件处理程序,因为KO会在删除元素时自动注销它们。

例如:

var someExternalObservable = ko.observable(123);
 
function SomeComponentViewModel() {
    this.myComputed = ko.computed(function() {
        return someExternalObservable() + 1;
    }, this);
 
    this.myPureComputed = ko.pureComputed(function() {
        return someExternalObservable() + 2;
    }, this);
 
    this.mySubscription = someExternalObservable.subscribe(function(val) {
        console.log('The external observable changed to ' + val);
    }, this);
 
    this.myIntervalHandle = window.setInterval(function() {
        console.log('Another second passed, and the component is still alive.');
    }, 1000);
}
 
SomeComponentViewModel.prototype.dispose = function() {
    this.myComputed.dispose();
    this.mySubscription.dispose();
    window.clearInterval(this.myIntervalHandle);
    // this.myPureComputed doesn't need to be manually disposed.
}
 
ko.components.register('your-component-name', {
    viewModel: SomeComponentViewModel,
    template: 'some template'
});

不必严格地需要仅仅依赖于相同viewmodel对象的属性来处理计算和订阅,因为这仅创建了JavaScript垃圾收集器知道如何释放的循环引用。 然而,为了避免不必记住哪些事情需要处理,你可能更喜欢在任何可能的地方使用pureComputed,并且显式地处置所有其他计算/订阅,无论技术上是否必要。

转载于:https://www.cnblogs.com/smallprogram/p/5973385.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个文档是我自己原创制作的,在别的网上肯定是没有的。 而且做得非常好看,和非常准确。 如果下载的人多,将会把中英文对照的版本也上传。 Knockout是一个以数据模型(data model)为基础的能够帮助你创建富文本,响应显示和编辑用户界面的JavaScript类库。任何时候如果你的UI需要自动更新(比如:更新依赖于用户的行为或者外部数据源的改变),KO能够很简单的帮你实现并且很容易维护。 重要特性: 优雅的依赖追踪 - 不管任何时候你的数据模型更新,都会自动更新相应的内容。 Elegant dependency tracking - automatically updates the right parts of your UI whenever your data model changes. 声明式绑定 - 浅显易懂的方式将你的用户界面指定部分关联到你的数据模型上。 Declarative bindings - a simple and obvious way to connect parts of your UI to your data model. You can construct a complex dynamic UIs easily using arbitrarily nested binding contexts. 轻易可扩展 - 几行代码就可以实现自定义行为作为新的声明式绑定。 Trivially extensible - implement custom behaviors as new declarative bindings for easy reuse in just a few lines of code. 额外的好处: 纯JavaScript类库 – 兼容任何服务器端和客户端技术 Pure JavaScript library - works with any server or client-side technology 可添加到Web程序最上部 – 不需要大的架构改变 Can be added on top of your existing web application - without requiring major architectural changes 简洁的 - Gzip之前大约25kb Compact - around 13kb after gzipping 兼容任何主流浏览器 - (IE 6+、Firefox 2+、Chrome、Safari、其它) Works on any mainstream browser - (IE 6+, Firefox 2+, Chrome, Safari, others) 采用行为驱动开发 - 意味着在新的浏览器和平台上可以很容易通过验证。 Comprehensive suite of specifications - (developed BDD-style) means its correct functioning can easily be verified on new browsers and platforms 开发人员如果用过Silverlight或者WPF可能会知道KO是MVVM模式的一个例子。如果熟悉 Ruby on Rails 或其它MVC技术可能会发现它是一个带有声明式语法的MVC实时form。换句话说,你可以把KO当成通过编辑JSON数据来制作UI用户界面的一种方式… 不管它为你做什么 Developers familiar with Ruby on Rails, ASP.NET MVC, or other MV* technologies may see MVVM as a real-time form of MVC with declarative syntax. In another sense, you can think of KO as a general way to make UIs for editing JSON data… whatever works for you :) OK, 如何使用它? 简单来说:声明你的数据作为一个JavaScript 模型对象(model object),然后将DOM 元素或者模板(templates)绑定到它上面. The quickest and most fun way to get started is by working through the interactive tutorials. Once you’ve got to grips with the basics, explore the live examples and then have a go with it in your own project. KO和jQuery (或Prototype等)是竞争关系还是能一起使用? 所有人都喜欢jQuery! 它是一个在页面里操作元素和事件的框架,非常出色并且易使用,在DOM操作上肯定使用jQuery,KO解决不同的问题。 Everyone loves jQuery! It’s an outstanding replacement for the clunky, inconsistent DOM API we had to put up with in the past. jQuery is an excellent low-level way to manipulate elements and event handlers in a web page. I certainly still use jQuery for low-level DOM manipulation. KO solves a different problem. 如果页面要求复杂,仅仅使用jQuery需要花费更多的代码。 例如:一个表格里显示一个列表,然后统计列表的数量,Add按钮在数据行TR小于5调的时候启用,否则就禁用。jQuery 没有基本的数据模型的概念,所以需要获取数据的数量(从table/div或者专门定义的CSS class),如果需要在某些SPAN里显示数据的数量,当添加新数据的时候,你还要记得更新这个SPAN的text。当然,你还要判断当总数>=5条的时候禁用Add按钮。 然后,如果还要实现Delete功能的时候,你不得不指出哪一个DOM元素被点击以后需要改变。 As soon as your UI gets nontrivial and has a few overlapping behaviors, things can get tricky and expensive to maintain if you only use jQuery. Consider an example: you’re displaying a list of items, stating the number of items in that list, and want to enable an ‘Add’ button only when there are fewer than 5 items. jQuery doesn’t have a concept of an underlying data model, so to get the number of items you have to infer it from the number of TRs in a table or the number of DIVs with a certain CSS class. Maybe the number of items is displayed in some SPAN, and you have to remember to update that SPAN’s text when the user adds an item. You also must remember to disable the ‘Add’ button when the number of TRs is 5. Later, you’re asked also to implement a ‘Delete’ button and you have to figure out which DOM elements to change whenever it’s clicked. Knockout的实现有何不同? 使用KO非常简单。将你的数据描绘成一个JavaScript数组对象myItems,然后使用模板(template)转化这个数组到表格里(或者一组DIV)。不管什么时候数组改变, UI界面也会响应改变(不用指出如何插入新行或在哪里插入),剩余的工作就是同步了。例如:你可以声明绑定如下一个SPAN显示数据数量(可以放在页面的任何地方,不一定非要在template里): It’s much easier with KO. It lets you scale up in complexity without fear of introducing inconsistencies. Just represent your items as a JavaScript array, and then use a foreach binding to transform this array into a TABLE or set of DIVs. Whenever the array changes, the UI changes to match (you don’t have to figure out how to inject new TRs or where to inject them). The rest of the UI stays in sync. For example, you can declaratively bind a SPAN to display the number of items as follows: There are <span data-bind="text: myItems().count"></span> items就是这些!你不需要写代码去更新它,它的更新依赖于数组myItems的改变。同样, Add按钮的启用和禁用依赖于数组 myItems 的长度,如下: That’s it! You don’t have to write code to update it; it updates on its own when the myItems array changes. Similarly, to make the ‘Add’ button enable or disable depending on the number of items, just write: <button data-bind="enable: myItems().count < 5">Add</button>之后,如果你要实现Delete功能,不必指出如何操作UI元素,只需要修改数据模型就可以了。 Later, when you’re asked to implement the ‘Delete’ functionality, you don’t have to figure out what bits of the UI it has to interact with; you just make it alter the underlying data model. 总结:KO没有和jQuery或类似的DOM 操作API对抗竞争。KO提供了一个关联数据模型和用户界面的高级功能。KO本身不依赖jQuery,但是你可以一起同时使用jQuery, 生动平缓的UI改变需要真正使用jQuery。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值