2

当我搜索“ Knockout Google Maps ”时,我发现相当多的基于 KO 的 Google Maps 实现。我能够找到的所有这些都采用了使用自定义绑定处理程序的方法,而我最初打算将其实现为 Knockout 组件。

例子:

谁能指出我正确的方向,为什么在这里更喜欢自定义绑定处理程序而不是 KO 组件

我计划的用例是这样的:

我正在实现一个带有地址搜索结果列表的页面。到目前为止的列表是一个 KO 组件,每个列表条目由另一个 KO 组件生成,该列表组件在 foreach 绑定中重复调用该组件。在这个搜索结果列表旁边,我需要一个谷歌地图,在地图中也显示结果条目。列表、列表条目和地图之间也会有相当多的交互。

这是我到目前为止所得到的:

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>

4

2 回答 2

6

组件和自定义处理程序是完全不同的东西。

自定义绑定

基本上自定义绑定可以访问:

  • 使用它的 HTML 组件
  • 绑定值(提供给绑定的表达式)
  • 元素中的所有其他绑定
  • 元素的绑定上下文,您可以从中访问$root$parent

它的定义包括两个功能:

  • init:允许进行初始设置,如初始化小部件、设置事件处理程序等
  • update: 它是在 之后调用的init。在那一刻,您可以通过绑定、所有元素绑定、上下文等访问属性(包括可观察的属性)。这将创建 subscriptios,当任何访问的 observable 发生更改时将调用 update。

因此,当您需要直接与 DOM 元素交互时,应使用自定义绑定,例如修改其属性、初始化小部件、订阅事件等

零件

一个组件是完全不同的。当你定义一个组件时,你必须定义:

  • 一个模板,它是一组 DOM 元素,通常带有绑定
  • 视图模型(通常是构造函数或工厂)

使用组件时:

  • 视图模型被实例化
  • 模板已加载
  • 视图模型绑定到模板

因此,组件允许重用视图模型和模板

那么,有什么区别呢?

自定义绑定可以直接访问 DOM 元素,允许与它们交互、订阅事件、修改属性等

组件只是一个视图模型,以及一组绑定到该特定视图模型的 DOM 元素。

因此,对于需要初始化一个小部件(地图)并与 Map 事件交互并响应可观察属性 cahnges 的 Google 地图,您永远不能使用组件,因为该组件不允许与DOM 元素。(记住是一堆带有绑定的 HTML 元素,以及相应的视图模型,它不能包含任何与这些元素交互的逻辑)。

自定义绑定通常适用于单个元素(尽管它可以处理其子元素,例如foreach)。对于谷歌地图,您只需要显示地图的元素。

组件通常是一组或多或少复杂的 DOM 元素,“从外部”无法访问这些元素。与主视图模型的唯一通信是通过参数完成的。组件不能直接与 DOM 元素交互:它必须通过 ko 绑定来完成。

所以,对于谷歌地图的情况,很明显你需要一个自定义绑定。

只有当您想要模块化或重用一组 DOM 元素和相关的视图模型时,创建组件才有意义,它还可以包括访问 Web 服务(通过 AJAX)、进行计算(通过使用计算的 observables 进行计算)等功能,等等。例如,可以使用一个组件来实现购物车,其中包括:

  • 用于显示购物车中项目的 DOM 元素(可能是 HTML 表格和一些控件)
  • 用于修改购物车内容的控件(例如用于删除元素或更改数量)
  • 显示总额、税金等的视图模型
  • 存储购物车以供以后使用或付费的功能(可能是对服务的 ajax 调用)

在这种情况下,购物车将有一个视图模型,其中包括计算出的 observables(显示总额和税金)、删除物品、修改数量、存储或支付等功能。还有一组具体的 DOM 元素,绑定了这个视图模型,即显示购物车并与之交互的 HTML。

在谷歌地图的情况下,如果没有自定义绑定的帮助或使用额外的非 ko 脚本,则无法使用组件。

如果您想在地图旁边显示一个地点列表并修改该列表,您可以使用一个组件,该组件将包含一个具有列表和相关功能的视图模型,以及一个包含具有 Google 地图自定义绑定的元素的模板。这是有道理的:viewmodel + 几个元素。

结论

这一切都意味着自定义绑定通常与绑定的 DOM 元素进行深度交互,而组件与元素的交互更高级别,这必须通过绑定来完成。

因此,它们在非常不同的层面上发挥作用。您无法比较或交换它们。

如果您坚持这样做,您可以创建一个行为类似于组件的绑定野兽,因为您可以完全控制元素并完全访问视图模型,但这比组件更难实现。并且可能也可以以某种深奥的方式反其道而行之。

于 2016-01-07T12:33:37.123 回答
1

捆绑

Binding,无论是否自定义,是一个非常简单的概念,涵盖两件事:

  1. UI 元素的属性发生变化,因此它应该更新一个对象(ViewModel)
  2. 对象 (ViewModel) 的属性发生变化,因此它应该更新 UI 元素。

从上面看,如果只实现了 1 个,则称为One Way Binding(因为如果您更改 UI,它会更新对象,但不会更新对象)。如果 1 和 2 都实现了,则称为双向绑定

因此,在任何时候,如果您认为需要执行此操作,则需要使用绑定,如果框架没有您需要的绑定,则自定义绑定。

最有可能的是,您所说的地图需要像上面这样的东西。它确实做到了,因为作者在第一段中这么说:

具体来说,您可以学习如何使地图标记成为 View 的一部分,并在后面的 ViewModel 发生更改时自动更改其位置。

看,上面作者讲了2:当ViewModel改变时,改变UI元素的位置。

零件

组件是具有可重用项目的概念,该项目可能具有但不一定具有 UI,并且与其一起打包工作所需的所有代码。这样就可以重复使用了。例如,它可能只是一个只允许数字的输入 UI 元素。它所需的所有代码都与 UI 元素一起打包。

现在与它一起打包的代码可能与绑定相关。如果他们使用的框架没有他们需要的绑定,它甚至可能有自定义绑定。此外,它可能还有与绑定无关的附加代码。

此外,一个组件可能有一个或多个 UI 元素。具有多个元素的组件的一个很好的例子是消息框。

综上所述

绑定和组件是分开的东西。一个组件内部可能有绑定,或者它可能有其他代码使其工作或两者兼而有之。

就您所说的地图而言,他们只是为其添加了一个功能:对 ViewModel 中的更改做出反应。它不是一个组件,因为它不是自包含和可重复使用的。

他们本可以使用组件来完成。但是,如果他们这样做并说它是一个 KO 组件,它可能仍然有 KO 特定的绑定代码与 ViewModel 和所需的所有 UI 元素一起打包。

于 2020-10-20T17:41:11.470 回答