Knockout Google 地图:组件与自定义绑定处理程序
Knockout Google Map: Component vs. Custom Binding Handler
当我 google“Knockout Google 地图”时,我发现相当多的基于 KO 的 Google 地图实现。我能够找到的所有这些都采用了使用自定义绑定处理程序的方法,而我最初打算将其实现为 Knockout 组件。
示例:
- http://www.codeproject.com/Articles/351298/KnockoutJS-and-Google-Maps-binding
- http://www.hoonzis.com/knockoutjs-and-google-maps-binding/
- https://github.com/manuel-guilbault/knockout.google.maps
任何人都可以指出我正确的方向为什么在这里比 KO 组件更喜欢自定义绑定处理程序?
我计划的用例是这样的:
我正在实现一个包含地址搜索结果列表的页面。到目前为止的列表是一个 KO 组件,每个列表条目都由另一个 KO 组件生成,列表组件在 foreach 绑定中重复调用该组件。在这个搜索结果列表旁边,我需要一个 google 地图来显示地图中的结果条目。列表、列表条目和地图之间也会有相当多的交互。
这是我目前得到的:
var GMap = function () {
var self = this;
var initMap = function() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 13,
center: {lat: 51.4387974, lng: 6.9922915}
});
};
initMap();
};
$(document).ready(function() {
ko.components.register('gmap', {
viewModel: GMap,
template: { element: 'gmap' }
});
ko.applyBindings();
});
#map {
height: 400px;
width: 600px;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.22"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<gmap></gmap>
<template id="gmap">
<div id="map"></div>
</template>
组件和自定义处理程序是完全不同的东西。
自定义绑定
基本上 custom binding 可以访问:
- 使用它的 HTML 组件
- 绑定值(提供给绑定的表达式)
- 元素中的所有其他绑定
- 元素的绑定上下文,从中可以访问
$root
、$parent
等
它的定义包括两个函数:
init
:允许进行初始设置,如初始化小部件、设置事件处理程序等
update
:在init
之后调用。在那一刻,您可以通过绑定、所有元素绑定、上下文等访问属性(包括可观察的属性)。这会创建 subscriptios,当任何访问的 observable 发生变化时,它会调用更新。
因此,当您需要直接与 DOM 元素交互时,应使用自定义绑定,例如修改其属性、初始化小部件、订阅事件等
组件
一个组件完全不同。当你定义一个组件时,你必须定义:
- 一个模板,它是一组 DOM 个元素,通常带有绑定
- 一个视图模型(通常是构造函数或工厂)
当您使用该组件时:
- 视图模型已实例化
- 模板已加载
- 视图模型绑定到模板
因此,组件允许重用视图模型和模板
所以,有什么区别?
自定义绑定可以直接访问 DOM 元素,允许与它们交互、订阅事件、修改属性等
一个组件只是一个视图模型,以及一组 DOM 绑定到该特定视图模型的元素。
因此,在 Google 地图的情况下,它需要初始化一个小部件(地图)并与地图事件交互,并响应可观察的属性变化,您永远不能使用组件,因为组件不允许与 DOM 元素直接交互。 (记住是一堆 HTML 具有绑定的元素,以及相应的视图模型,其中不能包含与这些元素交互的任何逻辑)。
自定义绑定通常适用于单个元素(尽管它可以处理其子元素,如 foreach
)。对于 Google 地图,您只需要显示地图的元素。
组件通常是一组或多或少复杂的 DOM 元素,“从外部”无法访问这些元素。与主视图模型的唯一通信是通过参数完成的。该组件不能直接与 DOM 元素交互:它必须通过 ko 绑定来实现。
因此,对于 Google 地图的情况,很明显您需要自定义绑定。
只有当您想模块化或重用一组 DOM 元素和相关的视图模型时,才有意义创建组件,它还可以包括访问 Web 服务等功能(通过 AJAX),进行计算(可能通过使用计算的可观察量),等等。例如,可以使用一个组件来实现购物车,其中包括:
- 用于显示购物车中商品的 DOM 元素(可能是 HTML table 和一些控件)
- 用于修改购物车内容的控件(例如删除元素或更改数量)
- 显示总计、税收等的视图模型
- 存储购物车以供日后使用或付款的功能(可以是 ajax 调用服务)
在这种情况下,购物车将有一个视图模型,其中包括计算出的可观察值(以显示总计和税收)、删除项目或修改数量、存储或支付等的功能。以及一组具体的 DOM 元素,具有此视图模型的绑定,即 HTML 以显示购物车并与之交互。
在 Google 地图的情况下,如果没有自定义绑定的帮助或 对其他非 ko 脚本的 hacky 使用,则无法使用组件 .
如果您想在地图旁边显示地点列表并修改该列表,您可以使用一个组件,其中包括一个带有列表和相关功能的视图模型,以及一个包含带有 Google 地图自定义绑定。这是有道理的:viewmodel + 几个元素。
结论
这一切都意味着自定义绑定通常与绑定的 DOM 元素有深度交互,而组件与元素有更高级别的交互,必须通过绑定来完成。
因此,它们在非常不同的层面上发挥着作用。您无法比较或互换它们。
如果你坚持这样做,你可以创造一个野兽f 一个行为类似于组件的绑定,因为您可以完全控制元素,并且可以完全访问视图模型,但这比组件更难实现。也可能以某种深奥的方式反过来做。
绑定
Binding,无论是否是习俗,都是一个非常简单的概念,涵盖两件事:
- UI 元素的 属性 发生变化,因此它应该更新对象 (ViewModel)
- 对象 (ViewModel) 的 属性 发生变化,因此它应该更新 UI 元素。
从上面如果只实现了1个,它被称为单向绑定(因为如果你改变UI,它会更新对象而不是另一个方式)。如果1和2都实现了,就叫Two Way Binding.
因此,如果您认为需要执行此操作,则任何时候都需要使用绑定,如果框架没有您需要的绑定,则需要自定义绑定。
很可能,您所说的地图需要像上面这样的东西。它确实做到了,因为作者在第一段中这样说:
Concretely, you can learn how to make the maps marker part of the View and automatically change its position any time when the ViewModel behind changes.
看,作者在上面讲了2:当ViewModel改变时,改变UI元素的位置。
组件
A component 是一个概念,即拥有一个可重复使用的项目,该项目可能具有 UI 但不一定,并且使其工作所需的所有代码都打包在一起它。这样它就可以重复使用。例如,它可能只是一个仅允许数字的输入 UI 元素。它所需的所有代码都与 UI 元素一起打包。
现在和它一起打包的代码可能与绑定相关的代码。如果他们使用的框架没有他们需要的绑定,它甚至可能有自定义绑定。此外,它可能还有与绑定无关的附加代码。
此外,一个组件可以有一个或多个 UI 元素。具有多个元素的组件的一个很好的例子是消息框。
总结
绑定和组件是不同的东西。一个组件可能在其中有绑定,或者它可能有其他代码来使其工作,或者两者兼而有之。
就您所说的地图而言,它们只添加了一个功能:对 ViewModel 中的变化做出反应。它不是一个组件,因为它不是独立的和可重复使用的。
他们本可以使用组件来完成。但是,如果他们这样做并说它是一个 KO 组件,它可能仍然有 KO 特定的绑定代码与它一起打包,以及 ViewModel 和所有需要的 UI 元素。
当我 google“Knockout Google 地图”时,我发现相当多的基于 KO 的 Google 地图实现。我能够找到的所有这些都采用了使用自定义绑定处理程序的方法,而我最初打算将其实现为 Knockout 组件。
示例:
- http://www.codeproject.com/Articles/351298/KnockoutJS-and-Google-Maps-binding
- http://www.hoonzis.com/knockoutjs-and-google-maps-binding/
- https://github.com/manuel-guilbault/knockout.google.maps
任何人都可以指出我正确的方向为什么在这里比 KO 组件更喜欢自定义绑定处理程序?
我计划的用例是这样的:
我正在实现一个包含地址搜索结果列表的页面。到目前为止的列表是一个 KO 组件,每个列表条目都由另一个 KO 组件生成,列表组件在 foreach 绑定中重复调用该组件。在这个搜索结果列表旁边,我需要一个 google 地图来显示地图中的结果条目。列表、列表条目和地图之间也会有相当多的交互。
这是我目前得到的:
var GMap = function () {
var self = this;
var initMap = function() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 13,
center: {lat: 51.4387974, lng: 6.9922915}
});
};
initMap();
};
$(document).ready(function() {
ko.components.register('gmap', {
viewModel: GMap,
template: { element: 'gmap' }
});
ko.applyBindings();
});
#map {
height: 400px;
width: 600px;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.22"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<gmap></gmap>
<template id="gmap">
<div id="map"></div>
</template>
组件和自定义处理程序是完全不同的东西。
自定义绑定
基本上 custom binding 可以访问:
- 使用它的 HTML 组件
- 绑定值(提供给绑定的表达式)
- 元素中的所有其他绑定
- 元素的绑定上下文,从中可以访问
$root
、$parent
等
它的定义包括两个函数:
init
:允许进行初始设置,如初始化小部件、设置事件处理程序等update
:在init
之后调用。在那一刻,您可以通过绑定、所有元素绑定、上下文等访问属性(包括可观察的属性)。这会创建 subscriptios,当任何访问的 observable 发生变化时,它会调用更新。
因此,当您需要直接与 DOM 元素交互时,应使用自定义绑定,例如修改其属性、初始化小部件、订阅事件等
组件
一个组件完全不同。当你定义一个组件时,你必须定义:
- 一个模板,它是一组 DOM 个元素,通常带有绑定
- 一个视图模型(通常是构造函数或工厂)
当您使用该组件时:
- 视图模型已实例化
- 模板已加载
- 视图模型绑定到模板
因此,组件允许重用视图模型和模板
所以,有什么区别?
自定义绑定可以直接访问 DOM 元素,允许与它们交互、订阅事件、修改属性等
一个组件只是一个视图模型,以及一组 DOM 绑定到该特定视图模型的元素。
因此,在 Google 地图的情况下,它需要初始化一个小部件(地图)并与地图事件交互,并响应可观察的属性变化,您永远不能使用组件,因为组件不允许与 DOM 元素直接交互。 (记住是一堆 HTML 具有绑定的元素,以及相应的视图模型,其中不能包含与这些元素交互的任何逻辑)。
自定义绑定通常适用于单个元素(尽管它可以处理其子元素,如 foreach
)。对于 Google 地图,您只需要显示地图的元素。
组件通常是一组或多或少复杂的 DOM 元素,“从外部”无法访问这些元素。与主视图模型的唯一通信是通过参数完成的。该组件不能直接与 DOM 元素交互:它必须通过 ko 绑定来实现。
因此,对于 Google 地图的情况,很明显您需要自定义绑定。
只有当您想模块化或重用一组 DOM 元素和相关的视图模型时,才有意义创建组件,它还可以包括访问 Web 服务等功能(通过 AJAX),进行计算(可能通过使用计算的可观察量),等等。例如,可以使用一个组件来实现购物车,其中包括:
- 用于显示购物车中商品的 DOM 元素(可能是 HTML table 和一些控件)
- 用于修改购物车内容的控件(例如删除元素或更改数量)
- 显示总计、税收等的视图模型
- 存储购物车以供日后使用或付款的功能(可以是 ajax 调用服务)
在这种情况下,购物车将有一个视图模型,其中包括计算出的可观察值(以显示总计和税收)、删除项目或修改数量、存储或支付等的功能。以及一组具体的 DOM 元素,具有此视图模型的绑定,即 HTML 以显示购物车并与之交互。
在 Google 地图的情况下,如果没有自定义绑定的帮助或 对其他非 ko 脚本的 hacky 使用,则无法使用组件 .
如果您想在地图旁边显示地点列表并修改该列表,您可以使用一个组件,其中包括一个带有列表和相关功能的视图模型,以及一个包含带有 Google 地图自定义绑定。这是有道理的:viewmodel + 几个元素。
结论
这一切都意味着自定义绑定通常与绑定的 DOM 元素有深度交互,而组件与元素有更高级别的交互,必须通过绑定来完成。
因此,它们在非常不同的层面上发挥着作用。您无法比较或互换它们。
如果你坚持这样做,你可以创造一个野兽f 一个行为类似于组件的绑定,因为您可以完全控制元素,并且可以完全访问视图模型,但这比组件更难实现。也可能以某种深奥的方式反过来做。
绑定
Binding,无论是否是习俗,都是一个非常简单的概念,涵盖两件事:
- UI 元素的 属性 发生变化,因此它应该更新对象 (ViewModel)
- 对象 (ViewModel) 的 属性 发生变化,因此它应该更新 UI 元素。
从上面如果只实现了1个,它被称为单向绑定(因为如果你改变UI,它会更新对象而不是另一个方式)。如果1和2都实现了,就叫Two Way Binding.
因此,如果您认为需要执行此操作,则任何时候都需要使用绑定,如果框架没有您需要的绑定,则需要自定义绑定。
很可能,您所说的地图需要像上面这样的东西。它确实做到了,因为作者在第一段中这样说:
Concretely, you can learn how to make the maps marker part of the View and automatically change its position any time when the ViewModel behind changes.
看,作者在上面讲了2:当ViewModel改变时,改变UI元素的位置。
组件
A component 是一个概念,即拥有一个可重复使用的项目,该项目可能具有 UI 但不一定,并且使其工作所需的所有代码都打包在一起它。这样它就可以重复使用。例如,它可能只是一个仅允许数字的输入 UI 元素。它所需的所有代码都与 UI 元素一起打包。
现在和它一起打包的代码可能与绑定相关的代码。如果他们使用的框架没有他们需要的绑定,它甚至可能有自定义绑定。此外,它可能还有与绑定无关的附加代码。
此外,一个组件可以有一个或多个 UI 元素。具有多个元素的组件的一个很好的例子是消息框。
总结
绑定和组件是不同的东西。一个组件可能在其中有绑定,或者它可能有其他代码来使其工作,或者两者兼而有之。
就您所说的地图而言,它们只添加了一个功能:对 ViewModel 中的变化做出反应。它不是一个组件,因为它不是独立的和可重复使用的。
他们本可以使用组件来完成。但是,如果他们这样做并说它是一个 KO 组件,它可能仍然有 KO 特定的绑定代码与它一起打包,以及 ViewModel 和所有需要的 UI 元素。