无论何时使用组件绑定或自定义元素注入组件,Knockout都将使用一个或多个组件装载器获取该组件的模板和视图模型。 组件加载器的任务是异步提供任何给定组件名称的模板/视图模型对。

本节目录

  • 默认组件加载器
  • 组件加载器实用函数
  • 实现自定义组件加载器
    • 可以实现的功能
      • getConfig(name, callback)
      • loadComponent(name, componentConfig, callback)
      • loadTemplate(name, templateConfig, callback)
      • loadViewModel(name, templateConfig, callback)
    • 注册自定义组件加载器
    • 控制优先级
    • 调用顺序
  • 示例1:设置命名约定的组件加载程序
  • 示例2:使用自定义代码加载外部文件的组件加载器
  • 注意1:自定义组件加载器和自定义元素
  • 注意2:与browserify集成

默认组件加载器

内置的默认组件加载器ko.components.defaultLoader基于组件定义的中心“注册表”。 它依赖于您明确注册每个组件的配置,然后才能使用该组件。

可参考第六章第一节。

组件加载器实用函数

以下函数读取和写入默认组件加载器的注册表:

  • ko.components.register(name, configuration)
    • 注册组件
  • ko.components.isRegistered(name)
    • 如果具有指定名称的组件已注册,则返回true;否则为假。
  • ko.components.unregister(name)
    • 从注册表中删除指定的组件。或者如果没有注册这样的组件,什么都不做。

以下函数在注册的组件加载器的完整列表中工作(不仅是默认加载器):

  • ko.components.get(name, callback)
    • 依次查询每个注册的加载器(默认情况下,只是默认加载器),找到第一个为命名的组件提供viewmodel /模板定义,然后调用回调来返回比viewmodel / template声明。如果没有注册的装载器知道这个组件,则调用回调(null)。
  • ko.components.clearCachedDefinition(name)
    • 通常,Knockout对每个组件名称查询加载器一次,然后缓存生成的定义。这确保了可以非常快速地实例化大量组件。如果要清除给定组件的缓存条目,请调用此方法,然后在下次需要该组件时再次查询加载程序。

此外,由于ko.components.defaultLoader是组件加载器,它实现以下标准组件加载器函数。您可以直接调用这些方法,例如,作为自定义加载器实施的一部分:

  • ko.components.defaultLoader.getConfig(name, callback)
  • ko.components.defaultLoader.loadComponent(name, componentConfig, callback)
  • ko.components.defaultLoader.loadTemplate(name, templateConfig, callback)
  • ko.components.defaultLoader.loadViewModel(name, viewModelConfig, callback)

实现自定义组件加载器

如果要使用命名约定而不是显式注册来加载组件,则可能需要实现自定义组件加载器。 或者,如果您想使用第三方“加载器”库从外部位置获取组件视图模型或模板。

可以实现的功能

自定义组件加载器只是一个对象,其属性是以下函数的任意组合:

getConfig(name, callback)

定义如下: 您希望基于名称以编程方式提供配置,例如,实现命名约定。

如果声明,Knockout将调用此函数为每个正在被实例化的组件获取一个配置对象。

  • 要提供配置,请调用回调(componentConfig),其中componentConfig是加载器或任何其他加载器上的loadComponent函数可以理解的任何对象。 默认加载器只提供使用ko.components.register注册的任何对象。
  • 例如,一个componentConfig像{template:'someElementId',viewModel:{require:'myModule'}}可以被默认加载器理解和实例化。
  • 您不限于以任何标准格式提供配置对象。 只要loadComponent函数理解它们,就可以提供任意对象。
  • 如果你不希望你的加载器提供一个命名组件的配置,那么callcallback(null)。 然后,Knockout将按顺序查询任何其他注册的装载器,直到提供非空值。
loadComponent(name, componentConfig, callback)

定义如下: 您想要控制组件配置的解释方式,例如,如果您不想使用标准的viewModel /模板对格式。

如果声明,Knockout将调用此函数将componentConfig对象转换为viewmodel /模板对。

  • 要提供一个viewmodel /模板对,请调用callback(result),其中result是具有以下属性的对象:

    • template - 必需。 DOM节点数组
    • createViewModel(params, componentInfo) - 可选。 稍后将调用的函数以为此组件的每个实例提供一个viewmodel对象
  • 如果你不希望你的加载器为给定的参数提供一个viewmodel /模板对,那么callcallback(null)。 然后,Knockout将按顺序查询任何其他注册的装载器,直到提供非空值。

loadTemplate(name, templateConfig, callback)

定义如下: 您想要使用自定义逻辑为给定模板配置提供DOM节点(例如,使用ajax请求通过URL提取模板)。

默认组件加载器将在声明它的任何注册加载器上调用此函数,将组件配置的template部分转换为DOM节点数组。 然后,为组件的每个实例缓存和克隆节点。

templateConfig值只是来自任何componentConfig对象的template属性。 例如,它可能包含“some markup”或{element:“someId”}或自定义格式,如{loadFromUrl:“someUrl.html”}。

  • 要提供DOM节点的数组,请调用回调(domNodeArray)。

  • 如果您不希望您的加载程序为给定的参数提供模板(例如,因为它不能识别配置格式),请调用callback(null)。 然后,Knockout将按顺序查询任何其他注册的装载器,直到提供非空值。

loadViewModel(name, templateConfig, callback)

定义如下: 您想要使用自定义逻辑为给定的viewmodel配置(例如,与第三方模块加载器或依赖注入系统集成)提供viewmodel工厂。

默认组件加载器将在声明它的任何注册加载器上调用此函数,将组件配置的viewModel部分转换为createViewModel工厂函数。 然后,该函数被缓存,并为需要viewmodel的组件的每个新实例调用。

viewModelConfig值只是来自任何componentConfig对象的viewModel属性。 例如,它可以是构造函数,或自定义格式,如{myViewModelType:'Something',options:{}}。

  • 要提供一个createViewModel函数,请调用回调(yourCreateViewModelFunction)。 ThecreateViewModel函数必须接受参数(params,componentInfo),并且必须在每次调用时同步返回一个新的viewmodel实例。

  • 如果你不希望你的加载器为给定的参数提供一个createViewModel函数(例如,因为它不能识别配置格式),call callback(null)。 然后,Knockout将按顺序查询任何其他注册的装载器,直到提供非空值。

注册自定义组件加载器

Knockout允许您同时使用多个组件加载器。 这是有用的,例如,您可以插入实现不同机制的加载器(例如,可以根据命名约定从后端服务器获取模板;另一个可以使用依赖注入系统设置视图模型)并使它们工作 一起。

因此,ko.components.loaders是一个包含当前启用的所有加载器的数组。 默认情况下,此数组只包含一个项目:ko.components.defaultLoader。 要添加额外的装载器,只需将它们插入到ko.components.loaders数组中。

控制优先级

如果希望自定义加载器优先于默认加载器(因此它获得第一次提供配置/值的机会),然后将其添加到数组的开头。 如果您希望默认加载器优先(因此您的自定义加载器仅为未显式注册的组件调用),然后将其添加到数组的末尾。

例:

// Adds myLowPriorityLoader to the end of the loaders array.
// It runs after other loaders, only if none of them returned a value.
ko.components.loaders.push(myLowPriorityLoader); // Adds myHighPriorityLoader to the beginning of the loaders array.
// It runs before other loaders, getting the first chance to return values.
ko.components.loaders.unshift(myHighPriorityLoader)

如果需要,您可以从装载器数组中删除ko.components.defaultLoader。

调用顺序

第一次Knockout需要构造一个具有给定名称的组件,它:

  • 依次调用每个注册的装载器的getConfig函数,直到第一个提供非nullcomponentConfig。

  • 然后,使用此componentConfig对象,依次调用每个注册的装载程序的loadComponent函数,直到第一个提供非空模板/ createViewModel对。

当默认加载器的loadComponent运行时,它同时:

  • 依次调用每个注册的装载器的loadTemplate函数,直到第一个提供非空的DOM数组。

    • 默认加载器本身有一个loadTemplate函数,它将一系列模板配置格式解析为DOM数组。
  • 依次调用每个注册的装载器的loadViewModel函数,直到第一个提供非空的createViewModel函数。
    • 默认加载器本身有一个loadViewModel函数,它将一系列viewmodel配置格式解析为createViewModel函数。

自定义加载器可以插入此过程的任何部分,因此您可以控制提供配置,解释配置,提供DOM节点或提供viewmodel工厂函数。通过将自定义加载器放入ko.components.loaders中的选定顺序,您可以控制不同加载策略的优先级顺序。

示例1:设置命名约定的组件加载程序

要实现命名约定,您的自定义组件加载器只需要实现getConfig。 例如:

var namingConventionLoader = {
getConfig: function(name, callback) {
// 1. Viewmodels are classes corresponding to the component name.
// e.g., my-component maps to MyApp.MyComponentViewModel
// 2. Templates are in elements whose ID is the component name
// plus '-template'.
var viewModelConfig = MyApp[toPascalCase(name) + 'ViewModel'],
templateConfig = { element: name + '-template' }; callback({ viewModel: viewModelConfig, template: templateConfig });
}
}; function toPascalCase(dasherized) {
return dasherized.replace(/(^|-)([a-z])/g, function (g, m1, m2) { return m2.toUpperCase(); });
} // Register it. Make it take priority over the default loader.
ko.components.loaders.unshift(namingConventionLoader);

现在已注册,您可以使用任何名称引用组件(无需预先注册它们),例如:

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

<!-- Declare template -->
<template id='my-component-template'>Hello World!</template> <script>
// Declare viewmodel
window.MyApp = window.MyApp || {};
MyApp.MyComponentViewModel = function(params) {
// ...
}
</script>

示例2:使用自定义代码加载外部文件的组件加载器

如果您的自定义加载器实现了loadTemplate和/或loadViewModel,那么您可以在加载过程中插入自定义代码。 您还可以使用这些函数来解释自定义配置格式。

例如,您可能需要启用以下配置格式:

ko.components.register('my-component', {
template: { fromUrl: 'file.html', maxCacheAge: 1234 },
viewModel: { viaLoader: '/path/myvm.js' }
});

...你可以使用自定义加载器。

以下自定义加载器将处理使用fromUrl值配置的加载模板:

var templateFromUrlLoader = {
loadTemplate: function(name, templateConfig, callback) {
if (templateConfig.fromUrl) {
// Uses jQuery's ajax facility to load the markup from a file
var fullUrl = '/templates/' + templateConfig.fromUrl + '?cacheAge=' + templateConfig.maxCacheAge;
$.get(fullUrl, function(markupString) {
// We need an array of DOM nodes, not a string.
// We can use the default loader to convert to the
// required format.
ko.components.defaultLoader.loadTemplate(name, markupString, callback);
});
} else {
// Unrecognized config format. Let another loader handle it.
callback(null);
}
}
}; // Register it
ko.components.loaders.unshift(templateFromUrlLoader);

...并且以下自定义加载器将负责加载使用签名加载器值配置的视图模型:

var viewModelCustomLoader = {
loadViewModel: function(name, viewModelConfig, callback) {
if (viewModelConfig.viaLoader) {
// You could use arbitrary logic, e.g., a third-party
// code loader, to asynchronously supply the constructor.
// For this example, just use a hard-coded constructor function.
var viewModelConstructor = function(params) {
this.prop1 = 123;
}; // We need a createViewModel function, not a plain constructor.
// We can use the default loader to convert to the
// required format.
ko.components.defaultLoader.loadViewModel(name, viewModelConstructor, callback);
} else {
// Unrecognized config format. Let another loader handle it.
callback(null);
}
}
}; // Register it
ko.components.loaders.unshift(viewModelCustomLoader);

如果你愿意,你可以将templateFromUrlLoader和viewModelCustomLoader结合到单个加载器中,方法是将loadTemplate和loadViewModel函数放在单个对象上。 然而,分离出这些问题是相当不错的,因为它们的实现是相当独立的。

注意1:自定义组件加载器和自定义元素

如果使用组件加载器通过命名约定获取组件,并且不使用ko.components.register注册组件,那么这些组件不会自动用作自定义元素(因为您还没告诉Knockout他们存在)。

请参阅:第六章 组件(4) 自定义元素

注意2:与browserify集成

Browserify是一个流行的库,用于以Node样式的同步require语法引用JavaScript库。它通常被认为是替代AMD加载器,如require.js。然而,Browserify解决了一个相当不同的问题:同步构建时参考解析,而不是由AMD处理的异步运行时参考解析。

因为Browserify是一个构建时间工具,它不需要真正需要与KO组件的任何特殊集成,并且没有必要实现任何类型的自定义组件加载器来使用它。您可以简单地使用Browserify的require语句来抓取您的组件视图模型的实例,然后显式地注册它们,例如:

// Note that the following *only* works with Browserify - not with require.js,
// since it relies on require() returning synchronously. ko.components.register('my-browserify-component', {
viewModel: require('myViewModel'),
template: require('fs').readFileSync(__dirname + '/my-template.html', 'utf8')
});

这使用brfs Browserify插件自动内联.html文件,因此您需要使用类似于以下命令构建脚本文件:

npm install brfs
browserify -t brfs main.js > bundle.js

章节结语

至此,KnockoutJS的组件介绍完毕,未来章节将介绍一些Knockout的其他技术。感谢你的阅读,希望我的这个KnockoutJS系列能够帮助到你,如果觉着文章不错,请点一波推荐,欢迎留言,转载请注明出处,http://www.cnblogs.com/smallprogram。谢谢

KnockoutJS 3.X API 第六章 组件(5) 高级应用组件加载器的更多相关文章

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

    组件绑定将指定的组件注入到元素中,并且可选地将参数传递给它. 本节目录 一个例子 API 组件生命周期 备注1:仅限模板组件 备注2:使用没有容器元素的组件 备注3:将标记传递给组件 处置和内存管理 ...

  2. KnockoutJS 3.X API 第六章 组件(2) 组件注册

    要使Knockout能够加载和实例化组件,必须使用ko.components.register注册它们,从而提供如此处所述的配置. 注意:作为替代,可以实现一个自定义组件加载器(自定义加载器下一节介绍 ...

  3. KnockoutJS 3.X API 第六章 组件(4) 自定义元素

    自定义元素提供了一种将组件注入视图的方便方法. 本节目录 介绍 例子 传递参数 父组件和子组件之间的通信 传递监控属性的表达式 将标记传递到组件中 控制自定义元素标记名称 注册自定义元素 备注1:将自 ...

  4. KnockoutJS 3.X API 第六章 组件(1) 组件和自定义元素 - 概述

    Components (组件)是一个强大的,干净的方式组织您的UI代码,可重复使用的块. : -可以表示单独的控件/窗口小部件或应用程序的整个部分 -包含自己的视图,通常(但可选)自己的视图模型 -可 ...

  5. Vue.js中用webpack合并打包多个组件并实现按需加载

    对于现在前端插件的频繁更新,所以多多少少要对组件化有点了解,下面这篇文章主要给大家介绍了在Vue.js中用webpack合并打包多个组件并实现按需加载的相关资料,需要的朋友可以参考下.   前言 随着 ...

  6. vue(组件、路由)懒加载

    const Login = resolve => require(['@/components/Login'], resolve) //就不用import了 Vue.use(Router) le ...

  7. Django---MTV和MVC的了解,Django的模版语言变量和逻辑,常见的模板语言过滤器,自定义过滤器,CSRF了解,Django的母版(继承extends,块block,组件include,静态文件的加载load static),自定义simple_tag和inclusion_tag

    Django---MTV和MVC的了解,Django的模版语言变量和逻辑,常见的模板语言过滤器,自定义过滤器,CSRF了解,Django的母版(继承extends,块block,组件include,静 ...

  8. keep-alive vue组件缓存避免多次加载相应的组件

    keep-alive vue组件缓存避免多次加载相应的组件

  9. react第七单元(组件的高级用法-组件的组合(children的用法)-高阶组件-封装组件)

    第七单元(组件的高级用法-组件的组合(children的用法)-高阶组件-封装组件) #受控组件 简而言之,就是受到状态state控制的表单,表单的值改变则state值也改变,受控组件必须要搭配onc ...

随机推荐

  1. Python爬虫学习(11):Beautiful Soup的使用

    之前我们从网页中提取重要信息主要是通过自己编写正则表达式完成的,但是如果你觉得正则表达式很好写的话,那你估计不是地球人了,而且很容易出问题.下边要介绍的Beautiful Soup就可以帮你简化这些操 ...

  2. C# 文件读写

    1.文本文件读写 //读 FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read); StreamReader ...

  3. Leetcode Maximum Product Subarray

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  4. Ajax跨域问题的两种解决方法

    浏览器不允许Ajax跨站请求,所以存在Ajax跨域问题,目前主要有两种办法解决. 1.在请求页面上使用Access-Control-Allow-Origin标头. 使用如下标头可以接受全部网站请求: ...

  5. Python3.5 day3作业一:实现简单的shell sed替换功能

    需求: 1.使python具有shell中sed替换功能. #!/usr/bin/env python #_*_conding:utf-8_*_ #sys模块用于传递参数,os模块用于与系统交互. i ...

  6. linux安装VMware-tools,

    系统中可能预装了open-vm-tools和VMware-tools冲突,所以需要先将前者卸载在进行安装不同系统卸载使用的命令不一样,centos的命令可以使用rpm,ubuntu的命令可以使用dpk ...

  7. Sublime Text 3 配置和使用方法

    下载: Sublime Text 3 官方下载地址 Sublime Text 3 汉化破解版 资料: Sublime Text 非官方文档   技巧 -用户或-User后缀的菜单项,其对应的配置文件都 ...

  8. java反射机制,通过类名获取对象,通过方法名和参数调

    import java.lang.reflect.Method;   import javax.persistence.Table; /**  * 通过注解javax.persistence.Tabl ...

  9. 学习建模 - UML

    最轻量级的工具下载地址 http://staruml.io/download 下载解压依赖:libgcrypt11 https://pan.baidu.com/s/1i3wb6M5 学习地址 http ...

  10. 一鼓作气 博客--第六篇 note6

    1.无论公司付给你多少,你的青春都是廉价的!! 2.通往财富自由之路 --得到APP 3.time 3.1 time.time() t = time.time() print(t) #--->1 ...