---
title: "<NuxtIsland>"
description: "Nuxt 提供了 <NuxtIsland> 组件，用于在不下载任何客户端 JS 的情况下渲染非交互式组件。"
canonical_url: "https://nuxt.zhcndoc.com/docs/4.x/api/components/nuxt-island"
---
# \<NuxtIsland>

> Nuxt 提供了 \<NuxtIsland> 组件，用于在不下载任何客户端 JS 的情况下渲染非交互式组件。

在渲染 island 组件时，island 组件的内容是静态的，因此客户端不会下载任何 JS。

更改 island 组件的 props 会触发对该 island 组件的重新获取以再次渲染它。

::tip
仅服务端组件在底层使用 `<NuxtIsland>`。
::

::read-more{to="https://nuxt.zhcndoc.com/docs/4.x/guide/concepts/server-components"}
阅读服务端组件和 island 的专门指南。
::

## 属性

- `name` : 要渲染的组件名称。
  - **类型**: `string`
  - **必填**
- `lazy`: 将组件设为非阻塞。
  - **类型**: `boolean`
  - **默认值**: `false`
- `props`: 传递给渲染组件的 props。
  - **类型**: `Record<string, any>`
- `source`: 调用要渲染的 island 的远程来源。
  - **类型**: `string`
- **dangerouslyLoadClientComponents**: 从远程来源加载组件时所必需。
  - **类型**: `boolean`
  - **默认值**: `false`

::note
远程 islands 需要在你的 `nuxt.config` 中将 `experimental.componentIslands` 设置为 `'local+remote'`。
::

::warning{icon="i-ph-warning-duotone"}
使用 `source` prop 从远程服务器渲染内容本质上是危险的。当你指定远程 `source` 时，你完全信任该服务器提供安全的 HTML 内容，这些内容会直接渲染到你的应用中。

这类似于使用带有外部内容的 `v-html` ——远程服务器可以注入任意 HTML，包括潜在的恶意内容。**请仅在完全信任和控制的服务器上使用 `source`。**

`dangerouslyLoadClientComponents` prop 控制另一层风险：是否也从远程来源下载并执行客户端组件。即使禁用 `dangerouslyLoadClientComponents`（默认值），你仍然信任远程服务器的 HTML 输出。
::

::note
组件 props 和上下文会作为 GET 查询参数发送，以便启用缓存。查询参数可能会出现在服务器访问日志、CDN 缓存和 HTTP `Referer` 标头中。
::

::note
默认情况下，会从 `~/components/islands/` 目录扫描组件 islands。因此 `~/components/islands/MyIsland.vue` 组件可以通过 `<NuxtIsland name="MyIsland" />` 来渲染。
::

## 已知限制

### 岛屿和服务端组件中的 `useId`

每个岛屿都会在服务端各自渲染到独立的 Vue 应用中，因此 Vue 的 [`useId`](https://vuejs.org/api/composition-api-helpers#useid) 计数器会为每个岛屿重新开始。因而，在某个岛屿内部生成的 id 可能会与同一页面上其他岛屿生成的 id，或与你应用其余部分生成的 id 发生冲突。

**解决方法**：在服务端插件中，根据岛屿上下文 id，为该岛屿的 Vue 应用设置一个不同的 [`idPrefix`](https://vuejs.org/api/application#app-config-idprefix)：

```ts [plugins/island-id-prefix.server.ts]
export default defineNuxtPlugin((nuxtApp) => {
  const islandContext = nuxtApp.ssrContext?.islandContext
  if (islandContext) {
    nuxtApp.vueApp.config.idPrefix = `${islandContext.id}-v`
  }
})
```

- **相同的岛屿仍然会共享相同的 ids。** 以相同名称、props 和上下文渲染的同一岛屿的两个实例，会共享一次服务端渲染（以及一个 payload 条目），因此它们的 HTML —— 包括任何由 `useId` 生成的 ids —— 都是相同的，而作为前缀使用的岛屿上下文 id 也相同。这会导致 DOM 中出现重复的 `id` 属性，从而可能破坏 `aria-*` 引用以及两个实例之间的 `<label for>` 关联。目前对此没有解决方法。
- **`useId` 在岛屿中的交互式组件内不起作用。** 使用 [`nuxt-client` 属性](https://nuxt.zhcndoc.com/docs/4.x/guide/concepts/server-components#selective-hydration-with-nuxt-client)加载的组件会在岛屿的应用中进行服务端渲染，但由主客户端应用进行水合，因此 `useId` 在服务端和客户端返回的值不同，导致水合不匹配。

## 插槽

如果声明了插槽（slot），则可以将插槽传递给 island 组件。

每个插槽都是交互式的，因为父组件是提供它的那一方。

有些插槽为 `NuxtIsland` 保留以处理特殊情况。

- `#fallback`: 指定在 island 加载之前（如果组件为 lazy）或 `NuxtIsland` 无法获取组件时要渲染的内容。

## 参考

- `refresh()`
  - **类型**: `() => Promise<void>`
  - **描述**: 通过重新获取来强制重新拉取服务端组件。

## 事件

- `error`
  - **参数**:
    - **error**:
      - **类型**: `unknown`
  - **描述**: 当 `NuxtIsland` 无法获取新的 island 时触发。

---

- [源码](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-island.ts)


## Sitemap

See the full [sitemap](https://nuxt.zhcndoc.com/sitemap.md) for all pages.
