You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nuxt3中使用Leaflet遇window未定义错误,求解决方案

问题描述

项目使用nuxt@^3.8.2和leaflet@^1.9.4,在Nuxt提供的ClientOnly组件内渲染地图仍出现window is not defined错误,相同代码在常规Vue项目中可正常运行。试过nuxt3-leaflet模块能正常工作,但该模块会在所有页面注入完整的Leaflet,导致无需地图的页面体积冗余,求解决办法。

父组件代码

<v-card class="rent__map">
    <RentMap />
</v-card>

地图组件代码

<template>
    <ClientOnly fallback-tag="div">
        <template #fallback>
            <div class="d-flex justify-center align-center" style="height: 100%;">
                <v-progress-circular indeterminate color="primary" />
            </div>
        </template>
        <div id="map"></div>
    </ClientOnly>
</template>
<script setup lang="ts">
import L from 'leaflet';
import "leaflet/dist/leaflet.css";

const zoom = ref(12);
const center = ref([27.700769, 85.300140]);
const map = ref<LMap | null>(null);
const tile = {
    url: "https://{s}.google.com/vt?lyrs=m&x={x}&y={y}&z={z}",
    attribution: "Google",
    layerType: "base",
    name: "OpenStreetMap",
    subDomains: ['mt0','mt1','mt2','mt3']
};

onMounted(() => {
    map.value = L.map('map').setView(center.value, zoom.value);
    L.tileLayer(tile.url, {
        attribution: tile.attribution,
        layerType: tile.layerType,
        name: tile.name,
        subdomains: tile.subDomains
    }).addTo(map.value);
});
</script>

错误信息

500
window is not defined

at ./node_modules/.pnpm/leaflet@1.9.4/node_modules/leaflet/dist/leaflet-src.js:7:66
at Object. (./node_modules/.pnpm/leaflet@1.9.4/node_modules/leaflet/dist/leaflet-src.js:10:3)
at Module._compile (node:internal/modules/cjs/loader:1241:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
at Module.load (node:internal/modules/cjs/loader:1091:32)
at Module._load (node:internal/modules/cjs/loader:938:12)
at cjsLoader (node:internal/modules/esm/translators:284:17)
at ModuleWrap. (node:internal/modules/esm/translators:234:7)
at ModuleJob.run (node:internal/modules/esm/module_job:217:25)

解决办法

1. 动态导入Leaflet,避免服务端加载

问题核心是静态导入L from 'leaflet'会在服务端渲染阶段执行,而Leaflet依赖window对象。改成客户端侧动态导入即可:

修改地图组件的<script setup>部分:

<script setup lang="ts">
import "leaflet/dist/leaflet.css"; // CSS不依赖window,可正常提前导入

const zoom = ref(12);
const center = ref([27.700769, 85.300140]);
const map = ref<L.Map | null>(null);
const tile = {
    url: "https://{s}.google.com/vt?lyrs=m&x={x}&y={y}&z={z}",
    attribution: "Google",
    layerType: "base",
    name: "OpenStreetMap",
    subDomains: ['mt0','mt1','mt2','mt3']
};

onMounted(async () => {
    // 仅在客户端动态加载Leaflet
    const L = await import('leaflet');
    map.value = L.map('map').setView(center.value, zoom.value);
    L.tileLayer(tile.url, {
        attribution: tile.attribution,
        layerType: tile.layerType,
        name: tile.name,
        subdomains: tile.subDomains
    }).addTo(map.value);
});
</script>

2. 给地图组件添加client:only指令(Nuxt 3特性)

在父组件引用RentMap时,加上client:only指令,强制组件仅在客户端渲染,彻底跳过服务端处理:

<v-card class="rent__map">
    <RentMap client:only />
</v-card>

这会确保组件的所有代码(包括导入逻辑)都不会在服务端执行,从根源避免window未定义问题。

3. 可选:补全TypeScript类型

如果使用TypeScript,动态导入后类型会丢失,可先安装类型包:

npm install @types/leaflet --save-dev

然后在组件顶部声明类型:

import type L from 'leaflet';

内容的提问来源于stack exchange,提问作者Kiran Parajuli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:36:04