使用作用域插槽与 Google Maps 的实际应用
基本示例
在某些情况下,您可能希望插槽内的模板能够访问负责渲染插槽内容的子组件的数据。这在您需要自由创建使用子组件数据属性的自定义模板时特别有用。这是作用域插槽的典型用例。
想象一个组件,它配置并准备一个外部 API 以供另一个组件使用,但没有与任何特定模板紧密耦合。然后,这样的组件可以在多个地方重复使用,渲染不同的模板,但使用相同的基对象和特定的 API。
我们将创建一个组件 (GoogleMapLoader.vue
),它
- 初始化 Google Maps API
- 创建
google
和map
对象 - 将这些对象暴露给使用
GoogleMapLoader
的父组件
以下是如何实现此目的的示例。我们将在下一节逐段分析代码,并了解实际发生的事情。
首先,让我们建立我们的 GoogleMapLoader.vue
模板
|
现在,我们的脚本需要传递一些 props 到组件,这使我们能够设置 Google Maps API 和 地图对象
|
这只是工作示例的一部分,您可以在下面的 Codesandbox 中找到完整的示例。
实际示例:创建 Google 地图加载器组件
1. 创建一个初始化我们地图的组件
GoogleMapLoader.vue
在模板中,我们为地图创建一个容器,该容器将用于挂载从 Google Maps API 中提取的 地图 对象。
|
接下来,我们的脚本需要从父组件接收 props,这将使我们能够设置 Google 地图。这些 props 包括
|
然后,我们将 google 和 map 的初始值设置为 null
|
在 mounted
钩子中,我们从 GoogleMapsApi
实例化 googleMapApi
和 Map
对象,并将 google
和 map
的值设置为创建的实例
|
到目前为止,一切都很好。完成所有这些操作后,我们可以继续将其他对象添加到地图(标记、折线等)并将其用作普通地图组件。
但是,我们希望将 GoogleMapLoader
组件仅用作准备地图的加载器 — 我们不想在其上渲染任何内容。
为了实现这一点,我们需要允许将使用 GoogleMapLoader
的父组件访问 this.google
和 this.map
,这些属性是在 GoogleMapLoader
组件内部设置的。这就是 作用域插槽 真正发挥作用的地方。作用域插槽允许我们将子组件中设置的属性暴露给父组件。这听起来可能像盗梦空间,但请再耐心等待一分钟,我们将进一步分解它。
2. 创建使用我们的初始化组件的组件。
TravelMap.vue
在模板中,我们渲染 GoogleMapLoader
组件并传递初始化地图所需的 props。
|
我们的脚本标签将如下所示
|
仍然没有作用域插槽,所以让我们添加一个。
3. 通过添加作用域插槽将 google
和 map
属性暴露给父组件。
最后,我们可以添加一个作用域插槽,它将完成这项工作,并允许我们在父组件中访问子组件 props。我们通过在子组件中添加 <slot>
标签并传递我们想要暴露的 props(使用 v-bind
指令或 :propName
简写)来做到这一点。它与将 props 传递给子组件没有什么不同,但在 <slot>
标签中执行此操作将反转数据流的方向。
GoogleMapLoader.vue
|
现在,当我们在子组件中拥有插槽时,我们需要在父组件中接收和使用暴露的 props。
4. 使用 slot-scope
属性在父组件中接收暴露的 props。
为了在父组件中接收 props,我们声明一个模板元素并使用 slot-scope
属性。此属性可以访问承载从子组件暴露的所有 props 的对象。我们可以获取整个对象,也可以 解构该对象 并仅获取我们需要的部分。
让我们解构这个东西来获取我们需要的部分。
TravelMap.vue
|
即使 google
和 map
props 不存在于 TravelMap
范围内,该组件也可以访问它们,我们可以在模板中使用它们。
您可能想知道为什么我们要这样做,以及这样做有什么用?
作用域插槽允许我们向插槽传递模板而不是渲染的元素。它被称为 作用域
插槽,因为它即使在父组件范围内渲染模板,也能够访问某些子组件数据。这使我们能够自由地用父组件的自定义内容填充模板。
5. 为标记和折线创建工厂组件
现在,当我们的地图准备就绪时,我们将创建两个工厂组件,它们将用于向 TravelMap
添加元素。
GoogleMapMarker.vue
|
GoogleMapLine.vue
|
这两个组件都接收 google
,我们使用它来提取所需的对象(标记或折线),以及 map
,它为我们提供了要放置元素的地图的引用。
每个组件还期望一个额外的 prop 来创建相应的元素。在本例中,我们分别有 marker
和 path
。
在 mounted
钩子中,我们创建一个元素(标记/折线)并通过将 map
属性传递给对象构造函数将其附加到我们的地图。
还有一步要走…
6. 向地图添加元素
让我们使用我们的工厂组件向地图添加元素。我们必须渲染工厂组件并传递 google
和 map
对象,以便数据流向正确的位置。
我们还需要提供元素本身所需的 data。在本例中,它是带有标记位置的 marker
对象和带有折线坐标的 path
对象。
就是这样,将数据点直接集成到模板中
|
我们需要在我们的脚本中导入所需的工厂组件,并设置将传递给标记和折线的 data
|
何时避免这种模式
根据示例创建非常复杂的解决方案可能很诱人,但在某些时候,我们可能会遇到这种抽象成为代码库中独立部分的情况。如果我们遇到了这种情况,可能值得考虑将其提取到一个附加组件中。
总结
就是这样。通过创建所有这些部分,我们现在可以通过向每个地图传递不同的模板来重复使用 GoogleMapLoader
组件作为所有地图的基础。想象一下,您需要创建另一个具有不同标记或仅具有标记而没有折线的地图。通过使用上述模式,这变得非常容易,因为我们只需要向 GoogleMapLoader
组件传递不同的内容。
这种模式并不严格与 Google 地图相关联;它可以与任何库一起使用,以设置基本组件并暴露库的 API,然后可以在调用基本组件的组件中使用该 API。